From be8621a2d5754c7b233e044eb2782917a0c0b6c8 Mon Sep 17 00:00:00 2001 From: <> Date: Tue, 30 May 2023 01:22:48 +0000 Subject: [PATCH] Deployed f8d64f1 with MkDocs version: 1.4.3 --- .nojekyll | 0 404.html | 349 + assets/_mkdocstrings.css | 36 + assets/images/favicon.png | Bin 0 -> 1870 bytes assets/javascripts/bundle.b4d07000.min.js | 29 + assets/javascripts/bundle.b4d07000.min.js.map | 8 + assets/javascripts/lunr/min/lunr.ar.min.js | 1 + assets/javascripts/lunr/min/lunr.da.min.js | 18 + assets/javascripts/lunr/min/lunr.de.min.js | 18 + assets/javascripts/lunr/min/lunr.du.min.js | 18 + assets/javascripts/lunr/min/lunr.es.min.js | 18 + assets/javascripts/lunr/min/lunr.fi.min.js | 18 + assets/javascripts/lunr/min/lunr.fr.min.js | 18 + assets/javascripts/lunr/min/lunr.hi.min.js | 1 + assets/javascripts/lunr/min/lunr.hu.min.js | 18 + assets/javascripts/lunr/min/lunr.hy.min.js | 1 + assets/javascripts/lunr/min/lunr.it.min.js | 18 + assets/javascripts/lunr/min/lunr.ja.min.js | 1 + assets/javascripts/lunr/min/lunr.jp.min.js | 1 + assets/javascripts/lunr/min/lunr.kn.min.js | 1 + assets/javascripts/lunr/min/lunr.ko.min.js | 1 + assets/javascripts/lunr/min/lunr.multi.min.js | 1 + assets/javascripts/lunr/min/lunr.nl.min.js | 18 + assets/javascripts/lunr/min/lunr.no.min.js | 18 + assets/javascripts/lunr/min/lunr.pt.min.js | 18 + assets/javascripts/lunr/min/lunr.ro.min.js | 18 + assets/javascripts/lunr/min/lunr.ru.min.js | 18 + assets/javascripts/lunr/min/lunr.sa.min.js | 1 + .../lunr/min/lunr.stemmer.support.min.js | 1 + assets/javascripts/lunr/min/lunr.sv.min.js | 18 + assets/javascripts/lunr/min/lunr.ta.min.js | 1 + assets/javascripts/lunr/min/lunr.te.min.js | 1 + assets/javascripts/lunr/min/lunr.th.min.js | 1 + assets/javascripts/lunr/min/lunr.tr.min.js | 18 + assets/javascripts/lunr/min/lunr.vi.min.js | 1 + assets/javascripts/lunr/min/lunr.zh.min.js | 1 + assets/javascripts/lunr/tinyseg.js | 206 + assets/javascripts/lunr/wordcut.js | 6708 +++++++++++++++++ .../workers/search.208ed371.min.js | 42 + .../workers/search.208ed371.min.js.map | 8 + assets/stylesheets/main.26e3688c.min.css | 1 + assets/stylesheets/main.26e3688c.min.css.map | 1 + assets/stylesheets/palette.ecc896b0.min.css | 1 + .../stylesheets/palette.ecc896b0.min.css.map | 1 + index.html | 4785 ++++++++++++ objects.inv | Bin 0 -> 148 bytes search/search_index.json | 1 + sitemap.xml | 3 + sitemap.xml.gz | Bin 0 -> 127 bytes 49 files changed, 12464 insertions(+) create mode 100644 .nojekyll create mode 100644 404.html create mode 100644 assets/_mkdocstrings.css create mode 100644 assets/images/favicon.png create mode 100644 assets/javascripts/bundle.b4d07000.min.js create mode 100644 assets/javascripts/bundle.b4d07000.min.js.map create mode 100644 assets/javascripts/lunr/min/lunr.ar.min.js create mode 100644 assets/javascripts/lunr/min/lunr.da.min.js create mode 100644 assets/javascripts/lunr/min/lunr.de.min.js create mode 100644 assets/javascripts/lunr/min/lunr.du.min.js create mode 100644 assets/javascripts/lunr/min/lunr.es.min.js create mode 100644 assets/javascripts/lunr/min/lunr.fi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.fr.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hu.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hy.min.js create mode 100644 assets/javascripts/lunr/min/lunr.it.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ja.min.js create mode 100644 assets/javascripts/lunr/min/lunr.jp.min.js create mode 100644 assets/javascripts/lunr/min/lunr.kn.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ko.min.js create mode 100644 assets/javascripts/lunr/min/lunr.multi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.nl.min.js create mode 100644 assets/javascripts/lunr/min/lunr.no.min.js create mode 100644 assets/javascripts/lunr/min/lunr.pt.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ro.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ru.min.js create mode 100644 assets/javascripts/lunr/min/lunr.sa.min.js create mode 100644 assets/javascripts/lunr/min/lunr.stemmer.support.min.js create mode 100644 assets/javascripts/lunr/min/lunr.sv.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ta.min.js create mode 100644 assets/javascripts/lunr/min/lunr.te.min.js create mode 100644 assets/javascripts/lunr/min/lunr.th.min.js create mode 100644 assets/javascripts/lunr/min/lunr.tr.min.js create mode 100644 assets/javascripts/lunr/min/lunr.vi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.zh.min.js create mode 100644 assets/javascripts/lunr/tinyseg.js create mode 100644 assets/javascripts/lunr/wordcut.js create mode 100644 assets/javascripts/workers/search.208ed371.min.js create mode 100644 assets/javascripts/workers/search.208ed371.min.js.map create mode 100644 assets/stylesheets/main.26e3688c.min.css create mode 100644 assets/stylesheets/main.26e3688c.min.css.map create mode 100644 assets/stylesheets/palette.ecc896b0.min.css create mode 100644 assets/stylesheets/palette.ecc896b0.min.css.map create mode 100644 index.html create mode 100644 objects.inv create mode 100644 search/search_index.json create mode 100644 sitemap.xml create mode 100644 sitemap.xml.gz diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/404.html b/404.html new file mode 100644 index 0000000..d391001 --- /dev/null +++ b/404.html @@ -0,0 +1,349 @@ + + + + + + + + + + + + + + + + + + Subtitles AI API Reference + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + + +
+
+
+ + + + +
+
+ +

404 - Not found

+ +
+
+ + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/assets/_mkdocstrings.css b/assets/_mkdocstrings.css new file mode 100644 index 0000000..a65078d --- /dev/null +++ b/assets/_mkdocstrings.css @@ -0,0 +1,36 @@ + +/* Don't capitalize names. */ +h5.doc-heading { + text-transform: none !important; +} + +/* Avoid breaking parameters name, etc. in table cells. */ +.doc-contents td code { + word-break: normal !important; +} + +/* For pieces of Markdown rendered in table cells. */ +.doc-contents td p { + margin-top: 0 !important; + margin-bottom: 0 !important; +} + +/* Max width for docstring sections tables. */ +.doc .md-typeset__table, +.doc .md-typeset__table table { + display: table !important; + width: 100%; +} +.doc .md-typeset__table tr { + display: table-row; +} + +/* Avoid line breaks in rendered fields. */ +.field-body p { + display: inline; +} + +/* Defaults in Spacy table style. */ +.doc-param-default { + float: right; +} diff --git a/assets/images/favicon.png b/assets/images/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..1cf13b9f9d978896599290a74f77d5dbe7d1655c GIT binary patch literal 1870 zcmV-U2eJ5xP)Gc)JR9QMau)O=X#!i9;T z37kk-upj^(fsR36MHs_+1RCI)NNu9}lD0S{B^g8PN?Ww(5|~L#Ng*g{WsqleV}|#l zz8@ri&cTzw_h33bHI+12+kK6WN$h#n5cD8OQt`5kw6p~9H3()bUQ8OS4Q4HTQ=1Ol z_JAocz`fLbT2^{`8n~UAo=#AUOf=SOq4pYkt;XbC&f#7lb$*7=$na!mWCQ`dBQsO0 zLFBSPj*N?#u5&pf2t4XjEGH|=pPQ8xh7tpx;US5Cx_Ju;!O`ya-yF`)b%TEt5>eP1ZX~}sjjA%FJF?h7cX8=b!DZl<6%Cv z*G0uvvU+vmnpLZ2paivG-(cd*y3$hCIcsZcYOGh{$&)A6*XX&kXZd3G8m)G$Zz-LV z^GF3VAW^Mdv!)4OM8EgqRiz~*Cji;uzl2uC9^=8I84vNp;ltJ|q-*uQwGp2ma6cY7 z;`%`!9UXO@fr&Ebapfs34OmS9^u6$)bJxrucutf>`dKPKT%%*d3XlFVKunp9 zasduxjrjs>f8V=D|J=XNZp;_Zy^WgQ$9WDjgY=z@stwiEBm9u5*|34&1Na8BMjjgf3+SHcr`5~>oz1Y?SW^=K z^bTyO6>Gar#P_W2gEMwq)ot3; zREHn~U&Dp0l6YT0&k-wLwYjb?5zGK`W6S2v+K>AM(95m2C20L|3m~rN8dprPr@t)5lsk9Hu*W z?pS990s;Ez=+Rj{x7p``4>+c0G5^pYnB1^!TL=(?HLHZ+HicG{~4F1d^5Awl_2!1jICM-!9eoLhbbT^;yHcefyTAaqRcY zmuctDopPT!%k+}x%lZRKnzykr2}}XfG_ne?nRQO~?%hkzo;@RN{P6o`&mMUWBYMTe z6i8ChtjX&gXl`nvrU>jah)2iNM%JdjqoaeaU%yVn!^70x-flljp6Q5tK}5}&X8&&G zX3fpb3E(!rH=zVI_9Gjl45w@{(ITqngWFe7@9{mX;tO25Z_8 zQHEpI+FkTU#4xu>RkN>b3Tnc3UpWzPXWm#o55GKF09j^Mh~)K7{QqbO_~(@CVq! zS<8954|P8mXN2MRs86xZ&Q4EfM@JB94b=(YGuk)s&^jiSF=t3*oNK3`rD{H`yQ?d; ztE=laAUoZx5?RC8*WKOj`%LXEkgDd>&^Q4M^z`%u0rg-It=hLCVsq!Z%^6eB-OvOT zFZ28TN&cRmgU}Elrnk43)!>Z1FCPL2K$7}gwzIc48NX}#!A1BpJP?#v5wkNprhV** z?Cpalt1oH&{r!o3eSKc&ap)iz2BTn_VV`4>9M^b3;(YY}4>#ML6{~(4mH+?%07*qo IM6N<$f(jP3KmY&$ literal 0 HcmV?d00001 diff --git a/assets/javascripts/bundle.b4d07000.min.js b/assets/javascripts/bundle.b4d07000.min.js new file mode 100644 index 0000000..3c0bdad --- /dev/null +++ b/assets/javascripts/bundle.b4d07000.min.js @@ -0,0 +1,29 @@ +"use strict";(()=>{var Ci=Object.create;var gr=Object.defineProperty;var Ri=Object.getOwnPropertyDescriptor;var ki=Object.getOwnPropertyNames,Ht=Object.getOwnPropertySymbols,Hi=Object.getPrototypeOf,yr=Object.prototype.hasOwnProperty,nn=Object.prototype.propertyIsEnumerable;var rn=(e,t,r)=>t in e?gr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,P=(e,t)=>{for(var r in t||(t={}))yr.call(t,r)&&rn(e,r,t[r]);if(Ht)for(var r of Ht(t))nn.call(t,r)&&rn(e,r,t[r]);return e};var on=(e,t)=>{var r={};for(var n in e)yr.call(e,n)&&t.indexOf(n)<0&&(r[n]=e[n]);if(e!=null&&Ht)for(var n of Ht(e))t.indexOf(n)<0&&nn.call(e,n)&&(r[n]=e[n]);return r};var Pt=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Pi=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of ki(t))!yr.call(e,o)&&o!==r&&gr(e,o,{get:()=>t[o],enumerable:!(n=Ri(t,o))||n.enumerable});return e};var yt=(e,t,r)=>(r=e!=null?Ci(Hi(e)):{},Pi(t||!e||!e.__esModule?gr(r,"default",{value:e,enumerable:!0}):r,e));var sn=Pt((xr,an)=>{(function(e,t){typeof xr=="object"&&typeof an!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(xr,function(){"use strict";function e(r){var n=!0,o=!1,i=null,s={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function a(O){return!!(O&&O!==document&&O.nodeName!=="HTML"&&O.nodeName!=="BODY"&&"classList"in O&&"contains"in O.classList)}function f(O){var Qe=O.type,De=O.tagName;return!!(De==="INPUT"&&s[Qe]&&!O.readOnly||De==="TEXTAREA"&&!O.readOnly||O.isContentEditable)}function c(O){O.classList.contains("focus-visible")||(O.classList.add("focus-visible"),O.setAttribute("data-focus-visible-added",""))}function u(O){O.hasAttribute("data-focus-visible-added")&&(O.classList.remove("focus-visible"),O.removeAttribute("data-focus-visible-added"))}function p(O){O.metaKey||O.altKey||O.ctrlKey||(a(r.activeElement)&&c(r.activeElement),n=!0)}function m(O){n=!1}function d(O){a(O.target)&&(n||f(O.target))&&c(O.target)}function h(O){a(O.target)&&(O.target.classList.contains("focus-visible")||O.target.hasAttribute("data-focus-visible-added"))&&(o=!0,window.clearTimeout(i),i=window.setTimeout(function(){o=!1},100),u(O.target))}function v(O){document.visibilityState==="hidden"&&(o&&(n=!0),Y())}function Y(){document.addEventListener("mousemove",N),document.addEventListener("mousedown",N),document.addEventListener("mouseup",N),document.addEventListener("pointermove",N),document.addEventListener("pointerdown",N),document.addEventListener("pointerup",N),document.addEventListener("touchmove",N),document.addEventListener("touchstart",N),document.addEventListener("touchend",N)}function B(){document.removeEventListener("mousemove",N),document.removeEventListener("mousedown",N),document.removeEventListener("mouseup",N),document.removeEventListener("pointermove",N),document.removeEventListener("pointerdown",N),document.removeEventListener("pointerup",N),document.removeEventListener("touchmove",N),document.removeEventListener("touchstart",N),document.removeEventListener("touchend",N)}function N(O){O.target.nodeName&&O.target.nodeName.toLowerCase()==="html"||(n=!1,B())}document.addEventListener("keydown",p,!0),document.addEventListener("mousedown",m,!0),document.addEventListener("pointerdown",m,!0),document.addEventListener("touchstart",m,!0),document.addEventListener("visibilitychange",v,!0),Y(),r.addEventListener("focus",d,!0),r.addEventListener("blur",h,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var cn=Pt(Er=>{(function(e){var t=function(){try{return!!Symbol.iterator}catch(c){return!1}},r=t(),n=function(c){var u={next:function(){var p=c.shift();return{done:p===void 0,value:p}}};return r&&(u[Symbol.iterator]=function(){return u}),u},o=function(c){return encodeURIComponent(c).replace(/%20/g,"+")},i=function(c){return decodeURIComponent(String(c).replace(/\+/g," "))},s=function(){var c=function(p){Object.defineProperty(this,"_entries",{writable:!0,value:{}});var m=typeof p;if(m!=="undefined")if(m==="string")p!==""&&this._fromString(p);else if(p instanceof c){var d=this;p.forEach(function(B,N){d.append(N,B)})}else if(p!==null&&m==="object")if(Object.prototype.toString.call(p)==="[object Array]")for(var h=0;hd[0]?1:0}),c._entries&&(c._entries={});for(var p=0;p1?i(d[1]):"")}})})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Er);(function(e){var t=function(){try{var o=new e.URL("b","http://a");return o.pathname="c d",o.href==="http://a/c%20d"&&o.searchParams}catch(i){return!1}},r=function(){var o=e.URL,i=function(f,c){typeof f!="string"&&(f=String(f)),c&&typeof c!="string"&&(c=String(c));var u=document,p;if(c&&(e.location===void 0||c!==e.location.href)){c=c.toLowerCase(),u=document.implementation.createHTMLDocument(""),p=u.createElement("base"),p.href=c,u.head.appendChild(p);try{if(p.href.indexOf(c)!==0)throw new Error(p.href)}catch(O){throw new Error("URL unable to set base "+c+" due to "+O)}}var m=u.createElement("a");m.href=f,p&&(u.body.appendChild(m),m.href=m.href);var d=u.createElement("input");if(d.type="url",d.value=f,m.protocol===":"||!/:/.test(m.href)||!d.checkValidity()&&!c)throw new TypeError("Invalid URL");Object.defineProperty(this,"_anchorElement",{value:m});var h=new e.URLSearchParams(this.search),v=!0,Y=!0,B=this;["append","delete","set"].forEach(function(O){var Qe=h[O];h[O]=function(){Qe.apply(h,arguments),v&&(Y=!1,B.search=h.toString(),Y=!0)}}),Object.defineProperty(this,"searchParams",{value:h,enumerable:!0});var N=void 0;Object.defineProperty(this,"_updateSearchParams",{enumerable:!1,configurable:!1,writable:!1,value:function(){this.search!==N&&(N=this.search,Y&&(v=!1,this.searchParams._fromString(this.search),v=!0))}})},s=i.prototype,a=function(f){Object.defineProperty(s,f,{get:function(){return this._anchorElement[f]},set:function(c){this._anchorElement[f]=c},enumerable:!0})};["hash","host","hostname","port","protocol"].forEach(function(f){a(f)}),Object.defineProperty(s,"search",{get:function(){return this._anchorElement.search},set:function(f){this._anchorElement.search=f,this._updateSearchParams()},enumerable:!0}),Object.defineProperties(s,{toString:{get:function(){var f=this;return function(){return f.href}}},href:{get:function(){return this._anchorElement.href.replace(/\?$/,"")},set:function(f){this._anchorElement.href=f,this._updateSearchParams()},enumerable:!0},pathname:{get:function(){return this._anchorElement.pathname.replace(/(^\/?)/,"/")},set:function(f){this._anchorElement.pathname=f},enumerable:!0},origin:{get:function(){var f={"http:":80,"https:":443,"ftp:":21}[this._anchorElement.protocol],c=this._anchorElement.port!=f&&this._anchorElement.port!=="";return this._anchorElement.protocol+"//"+this._anchorElement.hostname+(c?":"+this._anchorElement.port:"")},enumerable:!0},password:{get:function(){return""},set:function(f){},enumerable:!0},username:{get:function(){return""},set:function(f){},enumerable:!0}}),i.createObjectURL=function(f){return o.createObjectURL.apply(o,arguments)},i.revokeObjectURL=function(f){return o.revokeObjectURL.apply(o,arguments)},e.URL=i};if(t()||r(),e.location!==void 0&&!("origin"in e.location)){var n=function(){return e.location.protocol+"//"+e.location.hostname+(e.location.port?":"+e.location.port:"")};try{Object.defineProperty(e.location,"origin",{get:n,enumerable:!0})}catch(o){setInterval(function(){e.location.origin=n()},100)}}})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Er)});var qr=Pt((Mt,Nr)=>{/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(t,r){typeof Mt=="object"&&typeof Nr=="object"?Nr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Mt=="object"?Mt.ClipboardJS=r():t.ClipboardJS=r()})(Mt,function(){return function(){var e={686:function(n,o,i){"use strict";i.d(o,{default:function(){return Ai}});var s=i(279),a=i.n(s),f=i(370),c=i.n(f),u=i(817),p=i.n(u);function m(j){try{return document.execCommand(j)}catch(T){return!1}}var d=function(T){var E=p()(T);return m("cut"),E},h=d;function v(j){var T=document.documentElement.getAttribute("dir")==="rtl",E=document.createElement("textarea");E.style.fontSize="12pt",E.style.border="0",E.style.padding="0",E.style.margin="0",E.style.position="absolute",E.style[T?"right":"left"]="-9999px";var H=window.pageYOffset||document.documentElement.scrollTop;return E.style.top="".concat(H,"px"),E.setAttribute("readonly",""),E.value=j,E}var Y=function(T,E){var H=v(T);E.container.appendChild(H);var I=p()(H);return m("copy"),H.remove(),I},B=function(T){var E=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},H="";return typeof T=="string"?H=Y(T,E):T instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(T==null?void 0:T.type)?H=Y(T.value,E):(H=p()(T),m("copy")),H},N=B;function O(j){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?O=function(E){return typeof E}:O=function(E){return E&&typeof Symbol=="function"&&E.constructor===Symbol&&E!==Symbol.prototype?"symbol":typeof E},O(j)}var Qe=function(){var T=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},E=T.action,H=E===void 0?"copy":E,I=T.container,q=T.target,Me=T.text;if(H!=="copy"&&H!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(q!==void 0)if(q&&O(q)==="object"&&q.nodeType===1){if(H==="copy"&&q.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(H==="cut"&&(q.hasAttribute("readonly")||q.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Me)return N(Me,{container:I});if(q)return H==="cut"?h(q):N(q,{container:I})},De=Qe;function $e(j){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?$e=function(E){return typeof E}:$e=function(E){return E&&typeof Symbol=="function"&&E.constructor===Symbol&&E!==Symbol.prototype?"symbol":typeof E},$e(j)}function Ei(j,T){if(!(j instanceof T))throw new TypeError("Cannot call a class as a function")}function tn(j,T){for(var E=0;E0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof I.action=="function"?I.action:this.defaultAction,this.target=typeof I.target=="function"?I.target:this.defaultTarget,this.text=typeof I.text=="function"?I.text:this.defaultText,this.container=$e(I.container)==="object"?I.container:document.body}},{key:"listenClick",value:function(I){var q=this;this.listener=c()(I,"click",function(Me){return q.onClick(Me)})}},{key:"onClick",value:function(I){var q=I.delegateTarget||I.currentTarget,Me=this.action(q)||"copy",kt=De({action:Me,container:this.container,target:this.target(q),text:this.text(q)});this.emit(kt?"success":"error",{action:Me,text:kt,trigger:q,clearSelection:function(){q&&q.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(I){return vr("action",I)}},{key:"defaultTarget",value:function(I){var q=vr("target",I);if(q)return document.querySelector(q)}},{key:"defaultText",value:function(I){return vr("text",I)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(I){var q=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return N(I,q)}},{key:"cut",value:function(I){return h(I)}},{key:"isSupported",value:function(){var I=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],q=typeof I=="string"?[I]:I,Me=!!document.queryCommandSupported;return q.forEach(function(kt){Me=Me&&!!document.queryCommandSupported(kt)}),Me}}]),E}(a()),Ai=Li},828:function(n){var o=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function s(a,f){for(;a&&a.nodeType!==o;){if(typeof a.matches=="function"&&a.matches(f))return a;a=a.parentNode}}n.exports=s},438:function(n,o,i){var s=i(828);function a(u,p,m,d,h){var v=c.apply(this,arguments);return u.addEventListener(m,v,h),{destroy:function(){u.removeEventListener(m,v,h)}}}function f(u,p,m,d,h){return typeof u.addEventListener=="function"?a.apply(null,arguments):typeof m=="function"?a.bind(null,document).apply(null,arguments):(typeof u=="string"&&(u=document.querySelectorAll(u)),Array.prototype.map.call(u,function(v){return a(v,p,m,d,h)}))}function c(u,p,m,d){return function(h){h.delegateTarget=s(h.target,p),h.delegateTarget&&d.call(u,h)}}n.exports=f},879:function(n,o){o.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},o.nodeList=function(i){var s=Object.prototype.toString.call(i);return i!==void 0&&(s==="[object NodeList]"||s==="[object HTMLCollection]")&&"length"in i&&(i.length===0||o.node(i[0]))},o.string=function(i){return typeof i=="string"||i instanceof String},o.fn=function(i){var s=Object.prototype.toString.call(i);return s==="[object Function]"}},370:function(n,o,i){var s=i(879),a=i(438);function f(m,d,h){if(!m&&!d&&!h)throw new Error("Missing required arguments");if(!s.string(d))throw new TypeError("Second argument must be a String");if(!s.fn(h))throw new TypeError("Third argument must be a Function");if(s.node(m))return c(m,d,h);if(s.nodeList(m))return u(m,d,h);if(s.string(m))return p(m,d,h);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function c(m,d,h){return m.addEventListener(d,h),{destroy:function(){m.removeEventListener(d,h)}}}function u(m,d,h){return Array.prototype.forEach.call(m,function(v){v.addEventListener(d,h)}),{destroy:function(){Array.prototype.forEach.call(m,function(v){v.removeEventListener(d,h)})}}}function p(m,d,h){return a(document.body,m,d,h)}n.exports=f},817:function(n){function o(i){var s;if(i.nodeName==="SELECT")i.focus(),s=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var a=i.hasAttribute("readonly");a||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),a||i.removeAttribute("readonly"),s=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var f=window.getSelection(),c=document.createRange();c.selectNodeContents(i),f.removeAllRanges(),f.addRange(c),s=f.toString()}return s}n.exports=o},279:function(n){function o(){}o.prototype={on:function(i,s,a){var f=this.e||(this.e={});return(f[i]||(f[i]=[])).push({fn:s,ctx:a}),this},once:function(i,s,a){var f=this;function c(){f.off(i,c),s.apply(a,arguments)}return c._=s,this.on(i,c,a)},emit:function(i){var s=[].slice.call(arguments,1),a=((this.e||(this.e={}))[i]||[]).slice(),f=0,c=a.length;for(f;f{"use strict";/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */var rs=/["'&<>]/;Yo.exports=ns;function ns(e){var t=""+e,r=rs.exec(t);if(!r)return t;var n,o="",i=0,s=0;for(i=r.index;i0&&i[i.length-1])&&(c[0]===6||c[0]===2)){r=0;continue}if(c[0]===3&&(!i||c[1]>i[0]&&c[1]=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function W(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var n=r.call(e),o,i=[],s;try{for(;(t===void 0||t-- >0)&&!(o=n.next()).done;)i.push(o.value)}catch(a){s={error:a}}finally{try{o&&!o.done&&(r=n.return)&&r.call(n)}finally{if(s)throw s.error}}return i}function D(e,t,r){if(r||arguments.length===2)for(var n=0,o=t.length,i;n1||a(m,d)})})}function a(m,d){try{f(n[m](d))}catch(h){p(i[0][3],h)}}function f(m){m.value instanceof et?Promise.resolve(m.value.v).then(c,u):p(i[0][2],m)}function c(m){a("next",m)}function u(m){a("throw",m)}function p(m,d){m(d),i.shift(),i.length&&a(i[0][0],i[0][1])}}function pn(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof Ee=="function"?Ee(e):e[Symbol.iterator](),r={},n("next"),n("throw"),n("return"),r[Symbol.asyncIterator]=function(){return this},r);function n(i){r[i]=e[i]&&function(s){return new Promise(function(a,f){s=e[i](s),o(a,f,s.done,s.value)})}}function o(i,s,a,f){Promise.resolve(f).then(function(c){i({value:c,done:a})},s)}}function C(e){return typeof e=="function"}function at(e){var t=function(n){Error.call(n),n.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var It=at(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +`+r.map(function(n,o){return o+1+") "+n.toString()}).join(` + `):"",this.name="UnsubscriptionError",this.errors=r}});function Ve(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var Ie=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,n,o,i;if(!this.closed){this.closed=!0;var s=this._parentage;if(s)if(this._parentage=null,Array.isArray(s))try{for(var a=Ee(s),f=a.next();!f.done;f=a.next()){var c=f.value;c.remove(this)}}catch(v){t={error:v}}finally{try{f&&!f.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}else s.remove(this);var u=this.initialTeardown;if(C(u))try{u()}catch(v){i=v instanceof It?v.errors:[v]}var p=this._finalizers;if(p){this._finalizers=null;try{for(var m=Ee(p),d=m.next();!d.done;d=m.next()){var h=d.value;try{ln(h)}catch(v){i=i!=null?i:[],v instanceof It?i=D(D([],W(i)),W(v.errors)):i.push(v)}}}catch(v){n={error:v}}finally{try{d&&!d.done&&(o=m.return)&&o.call(m)}finally{if(n)throw n.error}}}if(i)throw new It(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)ln(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&Ve(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&Ve(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var Sr=Ie.EMPTY;function jt(e){return e instanceof Ie||e&&"closed"in e&&C(e.remove)&&C(e.add)&&C(e.unsubscribe)}function ln(e){C(e)?e():e.unsubscribe()}var Le={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var st={setTimeout:function(e,t){for(var r=[],n=2;n0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var n=this,o=this,i=o.hasError,s=o.isStopped,a=o.observers;return i||s?Sr:(this.currentObservers=null,a.push(r),new Ie(function(){n.currentObservers=null,Ve(a,r)}))},t.prototype._checkFinalizedStatuses=function(r){var n=this,o=n.hasError,i=n.thrownError,s=n.isStopped;o?r.error(i):s&&r.complete()},t.prototype.asObservable=function(){var r=new F;return r.source=this,r},t.create=function(r,n){return new xn(r,n)},t}(F);var xn=function(e){ie(t,e);function t(r,n){var o=e.call(this)||this;return o.destination=r,o.source=n,o}return t.prototype.next=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.next)===null||o===void 0||o.call(n,r)},t.prototype.error=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.error)===null||o===void 0||o.call(n,r)},t.prototype.complete=function(){var r,n;(n=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||n===void 0||n.call(r)},t.prototype._subscribe=function(r){var n,o;return(o=(n=this.source)===null||n===void 0?void 0:n.subscribe(r))!==null&&o!==void 0?o:Sr},t}(x);var Et={now:function(){return(Et.delegate||Date).now()},delegate:void 0};var wt=function(e){ie(t,e);function t(r,n,o){r===void 0&&(r=1/0),n===void 0&&(n=1/0),o===void 0&&(o=Et);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=n,i._timestampProvider=o,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=n===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,n),i}return t.prototype.next=function(r){var n=this,o=n.isStopped,i=n._buffer,s=n._infiniteTimeWindow,a=n._timestampProvider,f=n._windowTime;o||(i.push(r),!s&&i.push(a.now()+f)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var n=this._innerSubscribe(r),o=this,i=o._infiniteTimeWindow,s=o._buffer,a=s.slice(),f=0;f0?e.prototype.requestAsyncId.call(this,r,n,o):(r.actions.push(this),r._scheduled||(r._scheduled=ut.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,n,o){var i;if(o===void 0&&(o=0),o!=null?o>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,n,o);var s=r.actions;n!=null&&((i=s[s.length-1])===null||i===void 0?void 0:i.id)!==n&&(ut.cancelAnimationFrame(n),r._scheduled=void 0)},t}(Wt);var Sn=function(e){ie(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var n=this._scheduled;this._scheduled=void 0;var o=this.actions,i;r=r||o.shift();do if(i=r.execute(r.state,r.delay))break;while((r=o[0])&&r.id===n&&o.shift());if(this._active=!1,i){for(;(r=o[0])&&r.id===n&&o.shift();)r.unsubscribe();throw i}},t}(Dt);var Oe=new Sn(wn);var _=new F(function(e){return e.complete()});function Vt(e){return e&&C(e.schedule)}function Cr(e){return e[e.length-1]}function Ye(e){return C(Cr(e))?e.pop():void 0}function Te(e){return Vt(Cr(e))?e.pop():void 0}function zt(e,t){return typeof Cr(e)=="number"?e.pop():t}var pt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function Nt(e){return C(e==null?void 0:e.then)}function qt(e){return C(e[ft])}function Kt(e){return Symbol.asyncIterator&&C(e==null?void 0:e[Symbol.asyncIterator])}function Qt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function zi(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Yt=zi();function Gt(e){return C(e==null?void 0:e[Yt])}function Bt(e){return un(this,arguments,function(){var r,n,o,i;return $t(this,function(s){switch(s.label){case 0:r=e.getReader(),s.label=1;case 1:s.trys.push([1,,9,10]),s.label=2;case 2:return[4,et(r.read())];case 3:return n=s.sent(),o=n.value,i=n.done,i?[4,et(void 0)]:[3,5];case 4:return[2,s.sent()];case 5:return[4,et(o)];case 6:return[4,s.sent()];case 7:return s.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function Jt(e){return C(e==null?void 0:e.getReader)}function U(e){if(e instanceof F)return e;if(e!=null){if(qt(e))return Ni(e);if(pt(e))return qi(e);if(Nt(e))return Ki(e);if(Kt(e))return On(e);if(Gt(e))return Qi(e);if(Jt(e))return Yi(e)}throw Qt(e)}function Ni(e){return new F(function(t){var r=e[ft]();if(C(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function qi(e){return new F(function(t){for(var r=0;r=2;return function(n){return n.pipe(e?A(function(o,i){return e(o,i,n)}):de,ge(1),r?He(t):Dn(function(){return new Zt}))}}function Vn(){for(var e=[],t=0;t=2,!0))}function pe(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new x}:t,n=e.resetOnError,o=n===void 0?!0:n,i=e.resetOnComplete,s=i===void 0?!0:i,a=e.resetOnRefCountZero,f=a===void 0?!0:a;return function(c){var u,p,m,d=0,h=!1,v=!1,Y=function(){p==null||p.unsubscribe(),p=void 0},B=function(){Y(),u=m=void 0,h=v=!1},N=function(){var O=u;B(),O==null||O.unsubscribe()};return y(function(O,Qe){d++,!v&&!h&&Y();var De=m=m!=null?m:r();Qe.add(function(){d--,d===0&&!v&&!h&&(p=$r(N,f))}),De.subscribe(Qe),!u&&d>0&&(u=new rt({next:function($e){return De.next($e)},error:function($e){v=!0,Y(),p=$r(B,o,$e),De.error($e)},complete:function(){h=!0,Y(),p=$r(B,s),De.complete()}}),U(O).subscribe(u))})(c)}}function $r(e,t){for(var r=[],n=2;ne.next(document)),e}function K(e,t=document){return Array.from(t.querySelectorAll(e))}function z(e,t=document){let r=ce(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function ce(e,t=document){return t.querySelector(e)||void 0}function _e(){return document.activeElement instanceof HTMLElement&&document.activeElement||void 0}function tr(e){return L(b(document.body,"focusin"),b(document.body,"focusout")).pipe(ke(1),l(()=>{let t=_e();return typeof t!="undefined"?e.contains(t):!1}),V(e===_e()),J())}function Xe(e){return{x:e.offsetLeft,y:e.offsetTop}}function Kn(e){return L(b(window,"load"),b(window,"resize")).pipe(Ce(0,Oe),l(()=>Xe(e)),V(Xe(e)))}function rr(e){return{x:e.scrollLeft,y:e.scrollTop}}function dt(e){return L(b(e,"scroll"),b(window,"resize")).pipe(Ce(0,Oe),l(()=>rr(e)),V(rr(e)))}var Yn=function(){if(typeof Map!="undefined")return Map;function e(t,r){var n=-1;return t.some(function(o,i){return o[0]===r?(n=i,!0):!1}),n}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(r){var n=e(this.__entries__,r),o=this.__entries__[n];return o&&o[1]},t.prototype.set=function(r,n){var o=e(this.__entries__,r);~o?this.__entries__[o][1]=n:this.__entries__.push([r,n])},t.prototype.delete=function(r){var n=this.__entries__,o=e(n,r);~o&&n.splice(o,1)},t.prototype.has=function(r){return!!~e(this.__entries__,r)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(r,n){n===void 0&&(n=null);for(var o=0,i=this.__entries__;o0},e.prototype.connect_=function(){!Wr||this.connected_||(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),va?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){!Wr||!this.connected_||(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(t){var r=t.propertyName,n=r===void 0?"":r,o=ba.some(function(i){return!!~n.indexOf(i)});o&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),Gn=function(e,t){for(var r=0,n=Object.keys(t);r0},e}(),Jn=typeof WeakMap!="undefined"?new WeakMap:new Yn,Xn=function(){function e(t){if(!(this instanceof e))throw new TypeError("Cannot call a class as a function.");if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");var r=ga.getInstance(),n=new La(t,r,this);Jn.set(this,n)}return e}();["observe","unobserve","disconnect"].forEach(function(e){Xn.prototype[e]=function(){var t;return(t=Jn.get(this))[e].apply(t,arguments)}});var Aa=function(){return typeof nr.ResizeObserver!="undefined"?nr.ResizeObserver:Xn}(),Zn=Aa;var eo=new x,Ca=$(()=>k(new Zn(e=>{for(let t of e)eo.next(t)}))).pipe(g(e=>L(ze,k(e)).pipe(R(()=>e.disconnect()))),X(1));function he(e){return{width:e.offsetWidth,height:e.offsetHeight}}function ye(e){return Ca.pipe(S(t=>t.observe(e)),g(t=>eo.pipe(A(({target:r})=>r===e),R(()=>t.unobserve(e)),l(()=>he(e)))),V(he(e)))}function bt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function ar(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}var to=new x,Ra=$(()=>k(new IntersectionObserver(e=>{for(let t of e)to.next(t)},{threshold:0}))).pipe(g(e=>L(ze,k(e)).pipe(R(()=>e.disconnect()))),X(1));function sr(e){return Ra.pipe(S(t=>t.observe(e)),g(t=>to.pipe(A(({target:r})=>r===e),R(()=>t.unobserve(e)),l(({isIntersecting:r})=>r))))}function ro(e,t=16){return dt(e).pipe(l(({y:r})=>{let n=he(e),o=bt(e);return r>=o.height-n.height-t}),J())}var cr={drawer:z("[data-md-toggle=drawer]"),search:z("[data-md-toggle=search]")};function no(e){return cr[e].checked}function Ke(e,t){cr[e].checked!==t&&cr[e].click()}function Ue(e){let t=cr[e];return b(t,"change").pipe(l(()=>t.checked),V(t.checked))}function ka(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Ha(){return L(b(window,"compositionstart").pipe(l(()=>!0)),b(window,"compositionend").pipe(l(()=>!1))).pipe(V(!1))}function oo(){let e=b(window,"keydown").pipe(A(t=>!(t.metaKey||t.ctrlKey)),l(t=>({mode:no("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),A(({mode:t,type:r})=>{if(t==="global"){let n=_e();if(typeof n!="undefined")return!ka(n,r)}return!0}),pe());return Ha().pipe(g(t=>t?_:e))}function le(){return new URL(location.href)}function ot(e){location.href=e.href}function io(){return new x}function ao(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)ao(e,r)}function M(e,t,...r){let n=document.createElement(e);if(t)for(let o of Object.keys(t))typeof t[o]!="undefined"&&(typeof t[o]!="boolean"?n.setAttribute(o,t[o]):n.setAttribute(o,""));for(let o of r)ao(n,o);return n}function fr(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function so(){return location.hash.substring(1)}function Dr(e){let t=M("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function Pa(e){return L(b(window,"hashchange"),e).pipe(l(so),V(so()),A(t=>t.length>0),X(1))}function co(e){return Pa(e).pipe(l(t=>ce(`[id="${t}"]`)),A(t=>typeof t!="undefined"))}function Vr(e){let t=matchMedia(e);return er(r=>t.addListener(()=>r(t.matches))).pipe(V(t.matches))}function fo(){let e=matchMedia("print");return L(b(window,"beforeprint").pipe(l(()=>!0)),b(window,"afterprint").pipe(l(()=>!1))).pipe(V(e.matches))}function zr(e,t){return e.pipe(g(r=>r?t():_))}function ur(e,t={credentials:"same-origin"}){return ue(fetch(`${e}`,t)).pipe(fe(()=>_),g(r=>r.status!==200?Ot(()=>new Error(r.statusText)):k(r)))}function We(e,t){return ur(e,t).pipe(g(r=>r.json()),X(1))}function uo(e,t){let r=new DOMParser;return ur(e,t).pipe(g(n=>n.text()),l(n=>r.parseFromString(n,"text/xml")),X(1))}function pr(e){let t=M("script",{src:e});return $(()=>(document.head.appendChild(t),L(b(t,"load"),b(t,"error").pipe(g(()=>Ot(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(l(()=>{}),R(()=>document.head.removeChild(t)),ge(1))))}function po(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function lo(){return L(b(window,"scroll",{passive:!0}),b(window,"resize",{passive:!0})).pipe(l(po),V(po()))}function mo(){return{width:innerWidth,height:innerHeight}}function ho(){return b(window,"resize",{passive:!0}).pipe(l(mo),V(mo()))}function bo(){return G([lo(),ho()]).pipe(l(([e,t])=>({offset:e,size:t})),X(1))}function lr(e,{viewport$:t,header$:r}){let n=t.pipe(ee("size")),o=G([n,r]).pipe(l(()=>Xe(e)));return G([r,t,o]).pipe(l(([{height:i},{offset:s,size:a},{x:f,y:c}])=>({offset:{x:s.x-f,y:s.y-c+i},size:a})))}(()=>{function e(n,o){parent.postMessage(n,o||"*")}function t(...n){return n.reduce((o,i)=>o.then(()=>new Promise(s=>{let a=document.createElement("script");a.src=i,a.onload=s,document.body.appendChild(a)})),Promise.resolve())}var r=class extends EventTarget{constructor(n){super(),this.url=n,this.m=i=>{i.source===this.w&&(this.dispatchEvent(new MessageEvent("message",{data:i.data})),this.onmessage&&this.onmessage(i))},this.e=(i,s,a,f,c)=>{if(s===`${this.url}`){let u=new ErrorEvent("error",{message:i,filename:s,lineno:a,colno:f,error:c});this.dispatchEvent(u),this.onerror&&this.onerror(u)}};let o=document.createElement("iframe");o.hidden=!0,document.body.appendChild(this.iframe=o),this.w.document.open(),this.w.document.write(` + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + + +
+
+
+ + + + +
+
+ + + + + + + +

API Reference

+

️🎞 Subtitles generation tool (Web-UI + CLI + Python package) powered by OpenAI's Whisper and its variants 🎞️

+ + +
+ + + +

+ subsai.main + + +

+ +
+ +

SubsAI: Subtitles AI +Subtitles generation tool powered by OpenAI's Whisper and its variants.

+

This program is free software: you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +You should have received a copy of the GNU General Public License along with +this program. If not, see https://www.gnu.org/licenses/.

+ + + +
+ + + + + + + + +
+ + + +

+ SubsAI + + +

+ + +
+ + +

Subs AI class

+

Example usage: +

file = './assets/test1.mp4'
+subs_ai = SubsAI()
+model = subs_ai.create_model('openai/whisper', {'model_type': 'base'})
+subs = subs_ai.transcribe(file, model)
+subs.save('test1.srt')
+

+ + + + + +
+ + + + + + + + + +
+ + + +

+ available_models + + + + staticmethod + + +

+
available_models()
+
+ +
+ +

Returns the supported models

+ +

Returns:

+
    +
  • + list + –

    list of available models

    +
  • +
+ +
+ Source code in src/subsai/main.py +
53
+54
+55
+56
+57
+58
+59
+60
@staticmethod
+def available_models() -> list:
+    """
+    Returns the supported models
+
+    :return: list of available models
+    """
+    return list(AVAILABLE_MODELS.keys())
+
+
+
+ +
+ +
+ + + +

+ model_info + + + + staticmethod + + +

+
model_info(model)
+
+ +
+ +

Returns general infos about the model (brief description and url)

+ +

Parameters:

+
    +
  • + model + (str) + –

    model name

    +
  • +
+ +

Returns:

+
    +
  • + dict + –

    dict of infos

    +
  • +
+ +
+ Source code in src/subsai/main.py +
62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
@staticmethod
+def model_info(model: str) -> dict:
+    """
+    Returns general infos about the model (brief description and url)
+
+    :param model: model name
+
+    :return: dict of infos
+    """
+    return {'description': AVAILABLE_MODELS[model]['description'],
+            'url': AVAILABLE_MODELS[model]['url']}
+
+
+
+ +
+ +
+ + + +

+ config_schema + + + + staticmethod + + +

+
config_schema(model)
+
+ +
+ +

Returns the configs associated with a model

+ +

Parameters:

+
    +
  • + model + (str) + –

    model name

    +
  • +
+ +

Returns:

+
    +
  • + dict + –

    dict of configs

    +
  • +
+ +
+ Source code in src/subsai/main.py +
74
+75
+76
+77
+78
+79
+80
+81
+82
+83
@staticmethod
+def config_schema(model: str) -> dict:
+    """
+    Returns the configs associated with a model
+
+    :param model: model name
+
+    :return: dict of configs
+    """
+    return AVAILABLE_MODELS[model]['config_schema']
+
+
+
+ +
+ +
+ + + +

+ create_model + + + + staticmethod + + +

+
create_model(model_name, model_config={})
+
+ +
+ +

Returns a model instance

+ +

Parameters:

+
    +
  • + model_name + (str) + –

    the name of the model

    +
  • +
  • + model_config + (dict) + –

    the configuration dict

    +
  • +
+ +

Returns:

+
    +
  • + AbstractModel + –

    the model instance

    +
  • +
+ +
+ Source code in src/subsai/main.py +
85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
@staticmethod
+def create_model(model_name: str, model_config: dict = {}) -> AbstractModel:
+    """
+    Returns a model instance
+
+    :param model_name: the name of the model
+    :param model_config: the configuration dict
+
+    :return: the model instance
+    """
+    return AVAILABLE_MODELS[model_name]['class'](model_config)
+
+
+
+ +
+ +
+ + + +

+ transcribe + + + + staticmethod + + +

+
transcribe(media_file, model, model_config={})
+
+ +
+ +

Takes the model instance (created by :func:create_model) or the model name. +Returns a :class:pysubs2.SSAFile https://pysubs2.readthedocs.io/en/latest/api-reference.html#ssafile-a-subtitle-file`_

+ +

Parameters:

+
    +
  • + media_file + (str) + –

    path of the media file (video/audio)

    +
  • +
  • + model + (Union[AbstractModel, str]) + –

    model instance or model name

    +
  • +
  • + model_config + (dict) + –

    model configs' dict

    +
  • +
+ +

Returns:

+
    +
  • + SSAFile + –

    SSAFile: list of subtitles

    +
  • +
+ +
+ Source code in src/subsai/main.py +
 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
@staticmethod
+def transcribe(media_file: str, model: Union[AbstractModel, str], model_config: dict = {}) -> SSAFile:
+    """
+    Takes the model instance (created by :func:`create_model`) or the model name.
+    Returns a :class:`pysubs2.SSAFile` <https://pysubs2.readthedocs.io/en/latest/api-reference.html#ssafile-a-subtitle-file>`_
+
+    :param media_file: path of the media file (video/audio)
+    :param model: model instance or model name
+    :param model_config: model configs' dict
+
+    :return: SSAFile: list of subtitles
+    """
+    if type(model) == str:
+        stt_model = SubsAI.create_model(model, model_config)
+    else:
+        stt_model = model
+    media_file = str(pathlib.Path(media_file).resolve())
+    return stt_model.transcribe(media_file)
+
+
+
+ +
+ + + +
+ +
+ +
+ +
+ + + +

+ Tools + + +

+
Tools()
+
+ +
+ + +

Some tools related to subtitles processing (ex: translation)

+ + +
+ Source code in src/subsai/main.py +
122
+123
def __init__(self):
+    pass
+
+
+ + + +
+ + + + + + + + + +
+ + + +

+ available_translation_models + + + + staticmethod + + +

+
available_translation_models()
+
+ +
+ +

Returns available translation models +A simple link to :func:utils.available_translation_models for easy access

+ +

Returns:

+
    +
  • + list + –

    list of available models

    +
  • +
+ +
+ Source code in src/subsai/main.py +
125
+126
+127
+128
+129
+130
+131
+132
+133
+134
@staticmethod
+def available_translation_models() -> list:
+    """
+    Returns available translation models
+    A simple link to :func:`utils.available_translation_models` for easy access
+
+    :return: list of available models
+    """
+
+    return available_translation_models()
+
+
+
+ +
+ +
+ + + +

+ available_translation_languages + + + + staticmethod + + +

+
available_translation_languages(model)
+
+ +
+ +

Returns the languages supported by the translation model

+ +

Parameters:

+
    +
  • + model + (Union[str, TranslationModel]) + –

    the name of the model

    +
  • +
+ +

Returns:

+
    +
  • + list + –

    list of available languages

    +
  • +
+ +
+ Source code in src/subsai/main.py +
136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
@staticmethod
+def available_translation_languages(model: Union[str, TranslationModel]) -> list:
+    """
+    Returns the languages supported by the translation model
+
+    :param model: the name of the model
+    :return: list of available languages
+    """
+    if type(model) == str:
+        langs = Tools.create_translation_model(model).available_languages()
+    else:
+        langs = model.available_languages()
+    return langs
+
+
+
+ +
+ +
+ + + +

+ create_translation_model + + + + staticmethod + + +

+
create_translation_model(model_name='m2m100')
+
+ +
+ +

Creates and returns a translation model instance.

+ +

Parameters:

+
    +
  • + model_name + (str) + –

    name of the model. To get available models use :func:available_translation_models

    +
  • +
+ +

Returns:

+
    +
  • + TranslationModel + – +
  • +
+ +
+ Source code in src/subsai/main.py +
150
+151
+152
+153
+154
+155
+156
+157
+158
+159
@staticmethod
+def create_translation_model(model_name: str = "m2m100") -> TranslationModel:
+    """
+    Creates and returns a translation model instance.
+
+    :param model_name: name of the model. To get available models use :func:`available_translation_models`
+    :return:
+    """
+    mt = TranslationModel(model_name)
+    return mt
+
+
+
+ +
+ +
+ + + +

+ translate + + + + staticmethod + + +

+
translate(
+    subs,
+    source_language,
+    target_language,
+    model="m2m100",
+    translation_configs={},
+)
+
+ +
+ +

Translates a subtitles SSAFile object, what :func:SubsAI.transcribe is returning

+ +

Parameters:

+
    +
  • + subs + (SSAFile) + –

    SSAFile object

    +
  • +
  • + source_language + (str) + –

    the language of the subtitles

    +
  • +
  • + target_language + (str) + –

    the target language

    +
  • +
  • + model + (Union[str, TranslationModel]) + –

    the translation model, either an str or the model instance created by :func:create_translation_model

    +
  • +
  • + translation_configs + (dict) + –

    dict of translation configs (see :attr:configs.ADVANCED_TOOLS_CONFIGS)

    +
  • +
+ +

Returns:

+
    +
  • + SSAFile + –

    returns an SSAFile subtitles translated to the target language

    +
  • +
+ +
+ Source code in src/subsai/main.py +
161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
@staticmethod
+def translate(subs: SSAFile,
+              source_language: str,
+              target_language: str,
+              model: Union[str, TranslationModel] = "m2m100",
+              translation_configs: dict = {}) -> SSAFile:
+    """
+    Translates a subtitles `SSAFile` object, what :func:`SubsAI.transcribe` is returning
+
+    :param subs: `SSAFile` object
+    :param source_language: the language of the subtitles
+    :param target_language: the target language
+    :param model: the translation model, either an `str` or the model instance created by
+                    :func:`create_translation_model`
+    :param translation_configs: dict of translation configs (see :attr:`configs.ADVANCED_TOOLS_CONFIGS`)
+
+    :return: returns an `SSAFile` subtitles translated to the target language
+    """
+    if type(model) == str:
+        translation_model = Tools.create_translation_model(model)
+    else:
+        translation_model = model
+
+    translated_subs = SSAFile()
+    for sub in subs:
+        translated_sub = sub.copy()
+        translated_sub.text = translation_model.translate(text=sub.text,
+                                                          source=source_language,
+                                                          target=target_language,
+                                                          batch_size=translation_configs[
+                                                              'batch_size'] if 'batch_size' in translation_configs else 32,
+                                                          verbose=translation_configs[
+                                                              'verbose'] if 'verbose' in translation_configs else False)
+        translated_subs.append(translated_sub)
+    return translated_subs
+
+
+
+ +
+ +
+ + + +

+ auto_sync + + + + staticmethod + + +

+
auto_sync(subs, media_file, **kwargs)
+
+ +
+ +

Uses (ffsubsync)[https://github.com/smacke/ffsubsync] to auto-sync subtitles to the media file

+ +

Parameters:

+
    +
  • + subs + (SSAFile) + –

    SSAFile file

    +
  • +
  • + media_file + (str) + –

    path of the media_file

    +
  • +
  • + kwargs + –

    configs to pass to ffsubsync (see :attr:configs.ADVANCED_TOOLS_CONFIGS)

    +
  • +
+ +

Returns:

+
    +
  • + SSAFile + –

    SSAFile auto-synced

    +
  • +
+ +
+ Source code in src/subsai/main.py +
197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
@staticmethod
+def auto_sync(subs: SSAFile,
+              media_file: str,
+              **kwargs
+              ) -> SSAFile:
+    """
+    Uses (ffsubsync)[https://github.com/smacke/ffsubsync] to auto-sync subtitles to the media file
+
+    :param subs: `SSAFile` file
+    :param media_file: path of the media_file
+    :param kwargs: configs to pass to ffsubsync (see :attr:`configs.ADVANCED_TOOLS_CONFIGS`)
+
+    :return: `SSAFile` auto-synced
+    """
+    parser = make_parser()
+    srtin_file = tempfile.NamedTemporaryFile(delete=False)
+    srtout_file = tempfile.NamedTemporaryFile(delete=False)
+    try:
+        srtin = srtin_file.name + '.ass'
+        srtout = srtout_file.name + '.srt'
+        subs.save(srtin)
+        cmd = [media_file,
+               '-i', srtin,
+               '-o', srtout]
+        for config_name in kwargs:
+            value = kwargs[config_name]
+            if value is None or value is False:
+                continue
+            elif type(value) == bool and value is True:
+                cmd.append(f'--{config_name}')
+            else:
+                cmd.append(f'--{config_name}')
+                cmd.append(f'{value}')
+        parsed_args = parser.parse_args(cmd)
+        retval = run(parsed_args)["retval"]
+        synced_subs = pysubs2.load(srtout)
+        return synced_subs
+    finally:
+        srtin_file.close()
+        os.unlink(srtin_file.name)
+        srtout_file.close()
+        os.unlink(srtout_file.name)
+
+
+
+ +
+ + + +
+ +
+ +
+ + + + +
+ +
+ +
+ +
+ + + +

+ subsai.models + + +

+ +
+ + + +
+ + + + + + + + + + +
+ + + +

+ whisper_timestamped_model + + +

+ +
+ +

whisper_timestamped

+

See linto-ai/whisper-timestamped

+ + + +
+ + + + + + + + +
+ + + +

+ WhisperTimeStamped + + +

+
WhisperTimeStamped(model_config={})
+
+ +
+

+ Bases: AbstractModel

+ + + +
+ Source code in src/subsai/models/whisper_timestamped_model.py +
229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
def __init__(self, model_config={}):
+    super(WhisperTimeStamped, self).__init__(model_config=model_config,
+                                             model_name=self.model_name)
+    # config
+    self.model_type = _load_config('model_type', model_config, self.config_schema)
+    self.segment_type = _load_config('segment_type', model_config, self.config_schema)
+    self.device = _load_config('device', model_config, self.config_schema)
+    self.download_root = _load_config('download_root', model_config, self.config_schema)
+    self.in_memory = _load_config('in_memory', model_config, self.config_schema)
+
+    self.verbose = _load_config('verbose', model_config, self.config_schema)
+    self.temperature = _load_config('temperature', model_config, self.config_schema)
+    self.compression_ratio_threshold = _load_config('compression_ratio_threshold', model_config, self.config_schema)
+    self.logprob_threshold = _load_config('logprob_threshold', model_config, self.config_schema)
+    self.no_speech_threshold = _load_config('no_speech_threshold', model_config, self.config_schema)
+    self.condition_on_previous_text = _load_config('condition_on_previous_text', model_config, self.config_schema)
+
+    self.decode_options = \
+        {config: _load_config(config, model_config, self.config_schema)
+         for config in self.config_schema if not hasattr(self, config)}
+
+    self.model = whisper_timestamped.load_model(name=self.model_type,
+                                                device=self.device,
+                                                download_root=self.download_root,
+                                                in_memory=self.in_memory)
+
+
+ + + +
+ + + + + + + +
+ + + +
+ model_name + + + + instance-attribute + class-attribute + + +
+
model_name = 'linto-ai/whisper-timestamped'
+
+ +
+
+ +
+ +
+ + + +
+ config_schema + + + + instance-attribute + class-attribute + + +
+
config_schema = {
+    "model_type": {
+        "type": list,
+        "description": "One of the official model names listed by `whisper.available_models()`, or path to a model checkpoint containing the model dimensions and the model state_dict.",
+        "options": whisper_timestamped.available_models(),
+        "default": "base",
+    },
+    "segment_type": {
+        "type": list,
+        "description": "Whisper_timestamps gives the ability to have word-level timestamps, Choose here between sentence-level and word-level",
+        "options": ["sentence", "word"],
+        "default": "sentence",
+    },
+    "device": {
+        "type": list,
+        "description": "The PyTorch device to put the model into",
+        "options": [None, get_available_devices()],
+        "default": None,
+    },
+    "download_root": {
+        "type": str,
+        "description": "Path to download the model files; by default, it uses '~/.cache/whisper'",
+        "options": None,
+        "default": None,
+    },
+    "in_memory": {
+        "type": bool,
+        "description": "whether to preload the model weights into host memory",
+        "options": None,
+        "default": False,
+    },
+    "verbose": {
+        "type": bool,
+        "description": "Whether to display the text being decoded to the console. If True, displays all the details,If False, displays minimal details. If None, does not display anything",
+        "options": None,
+        "default": None,
+    },
+    "temperature": {
+        "type": Tuple,
+        "description": "Temperature for sampling. It can be a tuple of temperatures, which will be successively used upon failures according to either `compression_ratio_threshold` or `logprob_threshold`.",
+        "options": None,
+        "default": (0.0, 0.2, 0.4, 0.6, 0.8, 1.0),
+    },
+    "compression_ratio_threshold": {
+        "type": float,
+        "description": "If the gzip compression ratio is above this value, treat as failed",
+        "options": None,
+        "default": 2.4,
+    },
+    "logprob_threshold": {
+        "type": float,
+        "description": "If the average log probability over sampled tokens is below this value, treat as failed",
+        "options": None,
+        "default": -1.0,
+    },
+    "no_speech_threshold": {
+        "type": float,
+        "description": "If the no_speech probability is higher than this value AND the average log probability over sampled tokens is below `logprob_threshold`, consider the segment as silent",
+        "options": None,
+        "default": 0.6,
+    },
+    "condition_on_previous_text": {
+        "type": bool,
+        "description": "if True, the previous output of the model is provided as a prompt for the next window; disabling may make the text inconsistent across windows, but the model becomes less prone to getting stuck in a failure loop, such as repetition looping or timestamps going out of sync.",
+        "options": None,
+        "default": True,
+    },
+    "task": {
+        "type": list,
+        "description": "whether to perform X->X 'transcribe' or X->English 'translate'",
+        "options": ["transcribe", "translate"],
+        "default": "transcribe",
+    },
+    "language": {
+        "type": str,
+        "description": "language that the audio is in; uses detected language if None",
+        "options": None,
+        "default": None,
+    },
+    "sample_len": {
+        "type": int,
+        "description": "maximum number of tokens to sample",
+        "options": None,
+        "default": None,
+    },
+    "best_of": {
+        "type": int,
+        "description": "number of independent samples to collect, when t > 0",
+        "options": None,
+        "default": None,
+    },
+    "beam_size": {
+        "type": int,
+        "description": "number of beams in beam search, when t == 0",
+        "options": None,
+        "default": None,
+    },
+    "patience": {
+        "type": float,
+        "description": "patience in beam search (https://arxiv.org/abs/2204.05424)",
+        "options": None,
+        "default": None,
+    },
+    "length_penalty": {
+        "type": float,
+        "description": "'alpha' in Google NMT, None defaults to length norm",
+        "options": None,
+        "default": None,
+    },
+    "suppress_tokens": {
+        "type": str,
+        "description": 'list of tokens ids (or comma-separated token ids) to suppress "-1" will suppress a set of symbols as defined in `tokenizer.non_speech_tokens()`',
+        "options": None,
+        "default": "-1",
+    },
+    "fp16": {
+        "type": bool,
+        "description": "use fp16 for most of the calculation",
+        "options": None,
+        "default": True,
+    },
+    "remove_punctuation_from_words": {
+        "type": bool,
+        "description": "If False, words will be glued with the next punctuation mark (if any).If True, there will be no punctuation mark in the `words[:]['text']` list.It only affects these strings; This has no influence on the computation of the word confidence, whatever the value of `include_punctuation_in_confidence` is.",
+        "options": None,
+        "default": False,
+    },
+    "refine_whisper_precision": {
+        "type": float,
+        "description": "How much can we refine Whisper segment positions, in seconds. Must be a multiple of 0.02.",
+        "options": None,
+        "default": 0.5,
+    },
+    "min_word_duration": {
+        "type": float,
+        "description": "Minimum duration of a word, in seconds. If a word is shorter than this, timestamps will be adjusted.",
+        "options": None,
+        "default": 0.04,
+    },
+    "plot_word_alignment": {
+        "type": bool,
+        "description": "Whether to plot the word alignment for each segment. matplotlib must be installed to use this option.",
+        "options": None,
+        "default": False,
+    },
+    "seed": {
+        "type": int,
+        "description": "Random seed to use for temperature sampling, for the sake of reproducibility.Choose None for unpredictable randomness",
+        "options": None,
+        "default": 1234,
+    },
+    "vad": {
+        "type": bool,
+        "description": "Whether to perform voice activity detection (VAD) on the audio file, to remove silent parts before transcribing with Whisper model. This should decrease hallucinations from the Whisper model.",
+        "options": None,
+        "default": False,
+    },
+    "detect_disfluencies": {
+        "type": bool,
+        "description": 'Whether to detect disfluencies (i.e. hesitations, filler words, repetitions, corrections, etc.) that Whisper model might have omitted in the transcription. This should make the word timestamp prediction more accurate.And probable disfluencies will be marked as special words "[*]"',
+        "options": None,
+        "default": False,
+    },
+    "trust_whisper_timestamps": {
+        "type": bool,
+        "description": "Whether to rely on Whisper's timestamps to get approximative first estimate of segment positions (up to refine_whisper_precision).",
+        "options": None,
+        "default": True,
+    },
+    "naive_approach": {
+        "type": bool,
+        "description": "Force the naive approach that consists in decoding twice the audio file, once to get the transcription and once with the decoded tokens to get the alignment. Note that this approach is used anyway when beam_size is not None and/or when the temperature is a list with more than one element.",
+        "options": None,
+        "default": False,
+    },
+}
+
+ +
+
+ +
+ +
+ + + +
+ model_type + + + + instance-attribute + + +
+
model_type = _load_config(
+    "model_type", model_config, self.config_schema
+)
+
+ +
+
+ +
+ +
+ + + +
+ segment_type + + + + instance-attribute + + +
+
segment_type = _load_config(
+    "segment_type", model_config, self.config_schema
+)
+
+ +
+
+ +
+ +
+ + + +
+ device + + + + instance-attribute + + +
+
device = _load_config(
+    "device", model_config, self.config_schema
+)
+
+ +
+
+ +
+ +
+ + + +
+ download_root + + + + instance-attribute + + +
+
download_root = _load_config(
+    "download_root", model_config, self.config_schema
+)
+
+ +
+
+ +
+ +
+ + + +
+ in_memory + + + + instance-attribute + + +
+
in_memory = _load_config(
+    "in_memory", model_config, self.config_schema
+)
+
+ +
+
+ +
+ +
+ + + +
+ verbose + + + + instance-attribute + + +
+
verbose = _load_config(
+    "verbose", model_config, self.config_schema
+)
+
+ +
+
+ +
+ +
+ + + +
+ temperature + + + + instance-attribute + + +
+
temperature = _load_config(
+    "temperature", model_config, self.config_schema
+)
+
+ +
+
+ +
+ +
+ + + +
+ compression_ratio_threshold + + + + instance-attribute + + +
+
compression_ratio_threshold = _load_config(
+    "compression_ratio_threshold",
+    model_config,
+    self.config_schema,
+)
+
+ +
+
+ +
+ +
+ + + +
+ logprob_threshold + + + + instance-attribute + + +
+
logprob_threshold = _load_config(
+    "logprob_threshold", model_config, self.config_schema
+)
+
+ +
+
+ +
+ +
+ + + +
+ no_speech_threshold + + + + instance-attribute + + +
+
no_speech_threshold = _load_config(
+    "no_speech_threshold", model_config, self.config_schema
+)
+
+ +
+
+ +
+ +
+ + + +
+ condition_on_previous_text + + + + instance-attribute + + +
+
condition_on_previous_text = _load_config(
+    "condition_on_previous_text",
+    model_config,
+    self.config_schema,
+)
+
+ +
+
+ +
+ +
+ + + +
+ decode_options + + + + instance-attribute + + +
+
decode_options = {
+    config: _load_config(
+        config, model_config, self.config_schema
+    )
+    for config in self.config_schema
+    if not hasattr(self, config)
+}
+
+ +
+
+ +
+ +
+ + + +
+ model + + + + instance-attribute + + +
+
model = whisper_timestamped.load_model(
+    name=self.model_type,
+    device=self.device,
+    download_root=self.download_root,
+    in_memory=self.in_memory,
+)
+
+ +
+
+ +
+ + + +
+ + + +
+ transcribe + + +
+
transcribe(media_file)
+
+ +
+ +
+ Source code in src/subsai/models/whisper_timestamped_model.py +
255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
def transcribe(self, media_file) -> str:
+    audio = whisper_timestamped.load_audio(media_file)
+    results = whisper_timestamped.transcribe(self.model, audio,
+                                             verbose=self.verbose,
+                                             temperature=self.temperature,
+                                             compression_ratio_threshold=self.compression_ratio_threshold,
+                                             logprob_threshold=self.logprob_threshold,
+                                             no_speech_threshold=self.no_speech_threshold,
+                                             condition_on_previous_text=self.condition_on_previous_text,
+                                             **self.decode_options
+                                             )
+    subs = SSAFile()
+    if self.segment_type == 'word':  # word level timestamps
+        for segment in results['segments']:
+            for word in segment['words']:
+                event = SSAEvent(start=pysubs2.make_time(s=word["start"]), end=pysubs2.make_time(s=word["end"]))
+                event.plaintext = word["text"].strip()
+                subs.append(event)
+    elif self.segment_type == 'sentence':
+        for segment in results['segments']:
+            event = SSAEvent(start=pysubs2.make_time(s=segment["start"]), end=pysubs2.make_time(s=segment["end"]))
+            event.plaintext = segment["text"].strip()
+            subs.append(event)
+    else:
+        raise Exception(f'Unknown `segment_type` value, it should be one of the following: '
+                        f' {self.config_schema["segment_type"]["options"]}')
+    return subs
+
+
+
+ +
+ + + +
+ +
+ +
+ + + + +
+ +
+ +
+ +
+ + + +

+ abstract_model + + +

+ +
+ +

API that the transcription models should follow

+ + + +
+ + + + + + + + +
+ + + +

+ AbstractModel + + +

+
AbstractModel(model_name=None, model_config={})
+
+ +
+

+ Bases: ABC

+ + +

Abstract Model class

+ + +
+ Source code in src/subsai/models/abstract_model.py +
15
+16
+17
def __init__(self, model_name=None, model_config={}):
+    self.model_name = model_name
+    self.model_config = model_config
+
+
+ + + +
+ + + + + + + +
+ + + +
+ model_name + + + + instance-attribute + + +
+
model_name = model_name
+
+ +
+
+ +
+ +
+ + + +
+ model_config + + + + instance-attribute + + +
+
model_config = model_config
+
+ +
+
+ +
+ + + +
+ + + +
+ transcribe + + + + abstractmethod + + +
+
transcribe(media_file)
+
+ +
+ +

Transcribe the media_file to subtitles.

+

example use case from pysubs2.whisper:

+

.. code-block:: python + :linenos:

+

subs = SSAFile() +for segment in segments: + event = SSAEvent(start=make_time(s=segment["start"]), end=make_time(s=segment["end"])) + event.plaintext = segment["text"].strip() + subs.append(event)

+ +

Parameters:

+
    +
  • + media_file + –

    Path of the media file

    +
  • +
+ +

Returns:

+
    +
  • + SSAFile + –

    Collection of SSAEvent(s) (see :mod:pysubs2.ssaevent)

    +
  • +
+ +
+ Source code in src/subsai/models/abstract_model.py +
19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
@abstractmethod
+def transcribe(self, media_file) -> SSAFile:
+    """
+    Transcribe the `media_file` to subtitles.
+
+    example use case from pysubs2.whisper:
+
+    .. code-block:: python
+        :linenos:
+
+    subs = SSAFile()
+    for segment in segments:
+        event = SSAEvent(start=make_time(s=segment["start"]), end=make_time(s=segment["end"]))
+        event.plaintext = segment["text"].strip()
+        subs.append(event)
+
+    :param media_file: Path of the media file
+    :return: Collection of SSAEvent(s) (see :mod:`pysubs2.ssaevent`)
+    """
+    pass
+
+
+
+ +
+ + + +
+ +
+ +
+ + + + +
+ +
+ +
+ +
+ + + +

+ whisper_model + + +

+ +
+ +

Whisper Model

+

See openai/whisper

+ + + +
+ + + + + + + + +
+ + + +

+ WhisperModel + + +

+
WhisperModel(model_config)
+
+ +
+

+ Bases: AbstractModel

+ + + +
+ Source code in src/subsai/models/whisper_model.py +
181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
def __init__(self, model_config):
+    super(WhisperModel, self).__init__(model_config=model_config,
+                                       model_name=self.model_name)
+    # config
+    self.model_type = _load_config('model_type', model_config, self.config_schema)
+    self.device = _load_config('device', model_config, self.config_schema)
+    self.download_root = _load_config('download_root', model_config, self.config_schema)
+    self.in_memory = _load_config('in_memory', model_config, self.config_schema)
+
+    self.verbose = _load_config('verbose', model_config, self.config_schema)
+    self.temperature = _load_config('temperature', model_config, self.config_schema)
+    self.compression_ratio_threshold = _load_config('compression_ratio_threshold', model_config, self.config_schema)
+    self.logprob_threshold = _load_config('logprob_threshold', model_config, self.config_schema)
+    self.no_speech_threshold = _load_config('no_speech_threshold', model_config, self.config_schema)
+    self.condition_on_previous_text = _load_config('condition_on_previous_text', model_config, self.config_schema)
+
+    self.decode_options = \
+        {config: _load_config(config, model_config, self.config_schema)
+         for config in self.config_schema if not hasattr(self, config)}
+
+    self.model = whisper.load_model(name=self.model_type,
+                                    device=self.device,
+                                    download_root=self.download_root,
+                                    in_memory=self.in_memory)
+
+
+ + + +
+ + + + + + + +
+ + + +
+ model_name + + + + instance-attribute + class-attribute + + +
+
model_name = 'openai/whisper'
+
+ +
+
+ +
+ +
+ + + +
+ config_schema + + + + instance-attribute + class-attribute + + +
+
config_schema = {
+    "model_type": {
+        "type": list,
+        "description": "One of the official model names listed by `whisper.available_models()`, or path to a model checkpoint containing the model dimensions and the model state_dict.",
+        "options": whisper.available_models(),
+        "default": "base",
+    },
+    "device": {
+        "type": list,
+        "description": "The PyTorch device to put the model into",
+        "options": [None, get_available_devices()],
+        "default": None,
+    },
+    "download_root": {
+        "type": str,
+        "description": "Path to download the model files; by default, it uses '~/.cache/whisper'",
+        "options": None,
+        "default": None,
+    },
+    "in_memory": {
+        "type": bool,
+        "description": "whether to preload the model weights into host memory",
+        "options": None,
+        "default": False,
+    },
+    "verbose": {
+        "type": bool,
+        "description": "Whether to display the text being decoded to the console. If True, displays all the details,If False, displays minimal details. If None, does not display anything",
+        "options": None,
+        "default": None,
+    },
+    "temperature": {
+        "type": Tuple,
+        "description": "Temperature for sampling. It can be a tuple of temperatures, which will be successively used upon failures according to either `compression_ratio_threshold` or `logprob_threshold`.",
+        "options": None,
+        "default": (0.0, 0.2, 0.4, 0.6, 0.8, 1.0),
+    },
+    "compression_ratio_threshold": {
+        "type": float,
+        "description": "If the gzip compression ratio is above this value, treat as failed",
+        "options": None,
+        "default": 2.4,
+    },
+    "logprob_threshold": {
+        "type": float,
+        "description": "If the average log probability over sampled tokens is below this value, treat as failed",
+        "options": None,
+        "default": -1.0,
+    },
+    "no_speech_threshold": {
+        "type": float,
+        "description": "If the no_speech probability is higher than this value AND the average log probability over sampled tokens is below `logprob_threshold`, consider the segment as silent",
+        "options": None,
+        "default": 0.6,
+    },
+    "condition_on_previous_text": {
+        "type": bool,
+        "description": "if True, the previous output of the model is provided as a prompt for the next window; disabling may make the text inconsistent across windows, but the model becomes less prone to getting stuck in a failure loop, such as repetition looping or timestamps going out of sync.",
+        "options": None,
+        "default": True,
+    },
+    "task": {
+        "type": list,
+        "description": "whether to perform X->X 'transcribe' or X->English 'translate'",
+        "options": ["transcribe", "translate"],
+        "default": "transcribe",
+    },
+    "language": {
+        "type": str,
+        "description": "language that the audio is in; uses detected language if None",
+        "options": None,
+        "default": None,
+    },
+    "sample_len": {
+        "type": int,
+        "description": "maximum number of tokens to sample",
+        "options": None,
+        "default": None,
+    },
+    "best_of": {
+        "type": int,
+        "description": "number of independent samples to collect, when t > 0",
+        "options": None,
+        "default": None,
+    },
+    "beam_size": {
+        "type": int,
+        "description": "number of beams in beam search, when t == 0",
+        "options": None,
+        "default": None,
+    },
+    "patience": {
+        "type": float,
+        "description": "patience in beam search (https://arxiv.org/abs/2204.05424)",
+        "options": None,
+        "default": None,
+    },
+    "length_penalty": {
+        "type": float,
+        "description": "'alpha' in Google NMT, None defaults to length norm",
+        "options": None,
+        "default": None,
+    },
+    "prompt": {
+        "type": str,
+        "description": "text or tokens for the previous context",
+        "options": None,
+        "default": None,
+    },
+    "prefix": {
+        "type": str,
+        "description": "text or tokens to prefix the current context",
+        "options": None,
+        "default": None,
+    },
+    "suppress_blank": {
+        "type": bool,
+        "description": "this will suppress blank outputs",
+        "options": None,
+        "default": True,
+    },
+    "suppress_tokens": {
+        "type": str,
+        "description": 'list of tokens ids (or comma-separated token ids) to suppress "-1" will suppress a set of symbols as defined in `tokenizer.non_speech_tokens()`',
+        "options": None,
+        "default": "-1",
+    },
+    "without_timestamps": {
+        "type": bool,
+        "description": "use <|notimestamps|> to sample text tokens only",
+        "options": None,
+        "default": False,
+    },
+    "max_initial_timestamp": {
+        "type": float,
+        "description": "the initial timestamp cannot be later than this",
+        "options": None,
+        "default": 1.0,
+    },
+    "fp16": {
+        "type": bool,
+        "description": "use fp16 for most of the calculation",
+        "options": None,
+        "default": True,
+    },
+}
+
+ +
+
+ +
+ +
+ + + +
+ model_type + + + + instance-attribute + + +
+
model_type = _load_config(
+    "model_type", model_config, self.config_schema
+)
+
+ +
+
+ +
+ +
+ + + +
+ device + + + + instance-attribute + + +
+
device = _load_config(
+    "device", model_config, self.config_schema
+)
+
+ +
+
+ +
+ +
+ + + +
+ download_root + + + + instance-attribute + + +
+
download_root = _load_config(
+    "download_root", model_config, self.config_schema
+)
+
+ +
+
+ +
+ +
+ + + +
+ in_memory + + + + instance-attribute + + +
+
in_memory = _load_config(
+    "in_memory", model_config, self.config_schema
+)
+
+ +
+
+ +
+ +
+ + + +
+ verbose + + + + instance-attribute + + +
+
verbose = _load_config(
+    "verbose", model_config, self.config_schema
+)
+
+ +
+
+ +
+ +
+ + + +
+ temperature + + + + instance-attribute + + +
+
temperature = _load_config(
+    "temperature", model_config, self.config_schema
+)
+
+ +
+
+ +
+ +
+ + + +
+ compression_ratio_threshold + + + + instance-attribute + + +
+
compression_ratio_threshold = _load_config(
+    "compression_ratio_threshold",
+    model_config,
+    self.config_schema,
+)
+
+ +
+
+ +
+ +
+ + + +
+ logprob_threshold + + + + instance-attribute + + +
+
logprob_threshold = _load_config(
+    "logprob_threshold", model_config, self.config_schema
+)
+
+ +
+
+ +
+ +
+ + + +
+ no_speech_threshold + + + + instance-attribute + + +
+
no_speech_threshold = _load_config(
+    "no_speech_threshold", model_config, self.config_schema
+)
+
+ +
+
+ +
+ +
+ + + +
+ condition_on_previous_text + + + + instance-attribute + + +
+
condition_on_previous_text = _load_config(
+    "condition_on_previous_text",
+    model_config,
+    self.config_schema,
+)
+
+ +
+
+ +
+ +
+ + + +
+ decode_options + + + + instance-attribute + + +
+
decode_options = {
+    config: _load_config(
+        config, model_config, self.config_schema
+    )
+    for config in self.config_schema
+    if not hasattr(self, config)
+}
+
+ +
+
+ +
+ +
+ + + +
+ model + + + + instance-attribute + + +
+
model = whisper.load_model(
+    name=self.model_type,
+    device=self.device,
+    download_root=self.download_root,
+    in_memory=self.in_memory,
+)
+
+ +
+
+ +
+ + + +
+ + + +
+ transcribe + + +
+
transcribe(media_file)
+
+ +
+ +
+ Source code in src/subsai/models/whisper_model.py +
206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
def transcribe(self, media_file) -> str:
+    audio = whisper.load_audio(media_file)
+    result = self.model.transcribe(audio, verbose=self.verbose,
+                                   temperature=self.temperature,
+                                   compression_ratio_threshold=self.compression_ratio_threshold,
+                                   logprob_threshold=self.logprob_threshold,
+                                   no_speech_threshold=self.no_speech_threshold,
+                                   condition_on_previous_text=self.condition_on_previous_text,
+                                   **self.decode_options)
+    subs = pysubs2.load_from_whisper(result)
+    return subs
+
+
+
+ +
+ + + +
+ +
+ +
+ + + + +
+ +
+ +
+ +
+ + + +

+ whispercpp_model + + +

+ +
+ +

Whisper.cpp Model

+

See whisper.cpp, +See pywhispercpp

+ + + +
+ + + + + + + + +
+ + + +

+ WhisperCppModel + + +

+
WhisperCppModel(model_config)
+
+ +
+

+ Bases: AbstractModel

+ + + +
+ Source code in src/subsai/models/whispercpp_model.py +
230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
def __init__(self, model_config):
+    super(WhisperCppModel, self).__init__(model_config=model_config,
+                                       model_name=self.model_name)
+    # config
+    self.model_type = _load_config('model_type', model_config, self.config_schema)
+
+    self.params = {}
+    for config in self.config_schema:
+        if not hasattr(self, config):
+            config_value = _load_config(config, model_config, self.config_schema)
+            if config_value is None:
+                continue
+            self.params[config] = config_value
+
+    self.model = Model(model=self.model_type, **self.params)
+
+
+ + + +
+ + + + + + + +
+ + + +
+ model_name + + + + instance-attribute + class-attribute + + +
+
model_name = 'ggerganov/whisper.cpp'
+
+ +
+
+ +
+ +
+ + + +
+ config_schema + + + + instance-attribute + class-attribute + + +
+
config_schema = {
+    "model_type": {
+        "type": list,
+        "description": "Available whisper.cpp models",
+        "options": AVAILABLE_MODELS,
+        "default": "base",
+    },
+    "n_threads": {
+        "type": int,
+        "description": "Number of threads to allocate for the inferencedefault to min(4, available hardware_concurrency)",
+        "options": None,
+        "default": 4,
+    },
+    "n_max_text_ctx": {
+        "type": int,
+        "description": "max tokens to use from past text as prompt for the decoder",
+        "options": None,
+        "default": 16384,
+    },
+    "offset_ms": {
+        "type": int,
+        "description": "start offset in ms",
+        "options": None,
+        "default": 0,
+    },
+    "duration_ms": {
+        "type": int,
+        "description": "audio duration to process in ms",
+        "options": None,
+        "default": 0,
+    },
+    "translate": {
+        "type": bool,
+        "description": "whether to translate the audio to English",
+        "options": None,
+        "default": False,
+    },
+    "no_context": {
+        "type": bool,
+        "description": "do not use past transcription (if any) as initial prompt for the decoder",
+        "options": None,
+        "default": False,
+    },
+    "single_segment": {
+        "type": bool,
+        "description": "force single segment output (useful for streaming)",
+        "options": None,
+        "default": False,
+    },
+    "print_special": {
+        "type": bool,
+        "description": "print special tokens (e.g. <SOT>, <EOT>, <BEG>, etc.)",
+        "options": None,
+        "default": False,
+    },
+    "print_progress": {
+        "type": bool,
+        "description": "print progress information",
+        "options": None,
+        "default": True,
+    },
+    "print_realtime": {
+        "type": bool,
+        "description": "print results from within whisper.cpp (avoid it, use callback instead)",
+        "options": None,
+        "default": False,
+    },
+    "print_timestamps": {
+        "type": bool,
+        "description": "print timestamps for each text segment when printing realtime",
+        "options": None,
+        "default": True,
+    },
+    "token_timestamps": {
+        "type": bool,
+        "description": "enable token-level timestamps",
+        "options": None,
+        "default": False,
+    },
+    "thold_pt": {
+        "type": float,
+        "description": "timestamp token probability threshold (~0.01)",
+        "options": None,
+        "default": 0.01,
+    },
+    "thold_ptsum": {
+        "type": float,
+        "description": "timestamp token sum probability threshold (~0.01)",
+        "options": None,
+        "default": 0.01,
+    },
+    "max_len": {
+        "type": int,
+        "description": "max segment length in characters",
+        "options": None,
+        "default": 0,
+    },
+    "split_on_word": {
+        "type": bool,
+        "description": "split on word rather than on token (when used with max_len)",
+        "options": None,
+        "default": False,
+    },
+    "max_tokens": {
+        "type": int,
+        "description": "max tokens per segment (0 = no limit)",
+        "options": None,
+        "default": 0,
+    },
+    "speed_up": {
+        "type": bool,
+        "description": "speed-up the audio by 2x using Phase Vocoder",
+        "options": None,
+        "default": False,
+    },
+    "audio_ctx": {
+        "type": int,
+        "description": "overwrite the audio context size (0 = use default)",
+        "options": None,
+        "default": 0,
+    },
+    "prompt_n_tokens": {
+        "type": int,
+        "description": "tokens to provide to the whisper decoder as initial prompt",
+        "options": None,
+        "default": 0,
+    },
+    "language": {
+        "type": str,
+        "description": 'for auto-detection, set to None, "" or "auto"',
+        "options": None,
+        "default": "en",
+    },
+    "suppress_blank": {
+        "type": bool,
+        "description": "common decoding parameters",
+        "options": None,
+        "default": True,
+    },
+    "suppress_non_speech_tokens": {
+        "type": bool,
+        "description": "common decoding parameters",
+        "options": None,
+        "default": False,
+    },
+    "temperature": {
+        "type": float,
+        "description": "initial decoding temperature",
+        "options": None,
+        "default": 0.0,
+    },
+    "max_initial_ts": {
+        "type": float,
+        "description": "max_initial_ts",
+        "options": None,
+        "default": 1.0,
+    },
+    "length_penalty": {
+        "type": float,
+        "description": "length_penalty",
+        "options": None,
+        "default": -1.0,
+    },
+    "temperature_inc": {
+        "type": float,
+        "description": "temperature_inc",
+        "options": None,
+        "default": 0.2,
+    },
+    "entropy_thold": {
+        "type": float,
+        "description": 'similar to OpenAI\'s "compression_ratio_threshold"',
+        "options": None,
+        "default": 2.4,
+    },
+    "logprob_thold": {
+        "type": float,
+        "description": "logprob_thold",
+        "options": None,
+        "default": -1.0,
+    },
+    "no_speech_thold": {
+        "type": float,
+        "description": "no_speech_thold",
+        "options": None,
+        "default": 0.6,
+    },
+    "greedy": {
+        "type": dict,
+        "description": "greedy",
+        "options": None,
+        "default": {"best_of": -1},
+    },
+    "beam_search": {
+        "type": dict,
+        "description": "beam_search",
+        "options": None,
+        "default": {"beam_size": -1, "patience": -1.0},
+    },
+}
+
+ +
+
+ +
+ +
+ + + +
+ model_type + + + + instance-attribute + + +
+
model_type = _load_config(
+    "model_type", model_config, self.config_schema
+)
+
+ +
+
+ +
+ +
+ + + +
+ params + + + + instance-attribute + + +
+
params = {}
+
+ +
+
+ +
+ +
+ + + +
+ model + + + + instance-attribute + + +
+
model = Model(model=self.model_type, None=self.params)
+
+ +
+
+ +
+ + + +
+ + + +
+ transcribe + + +
+
transcribe(media_file)
+
+ +
+ +
+ Source code in src/subsai/models/whispercpp_model.py +
246
+247
+248
+249
+250
+251
+252
+253
def transcribe(self, media_file) -> str:
+    segments = self.model.transcribe(media=media_file)
+    subs = SSAFile()
+    for seg in segments:
+        event = SSAEvent(start=seg.t0*10, end=seg.t1*10)
+        event.plaintext = seg.text.strip()
+        subs.append(event)
+    return subs
+
+
+
+ +
+ + + +
+ +
+ +
+ + + + +
+ +
+ +
+ +
+ + + +

+ faster_whisper_model + + +

+ +
+ +

Faster Whisper Model

+

See guillaumekln/faster-whisper

+ + + +
+ + + + + + + + +
+ + + +

+ FasterWhisperModel + + +

+
FasterWhisperModel(model_config)
+
+ +
+

+ Bases: AbstractModel

+ + + +
+ Source code in src/subsai/models/faster_whisper_model.py +
224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
def __init__(self, model_config):
+    super(FasterWhisperModel, self).__init__(model_config=model_config,
+                                       model_name=self.model_name)
+    # config
+    self._model_size_or_path = _load_config('model_size_or_path', model_config, self.config_schema)
+    self._device = _load_config('device', model_config, self.config_schema)
+    self._device_index = _load_config('device_index', model_config, self.config_schema)
+    self._compute_type = _load_config('compute_type', model_config, self.config_schema)
+    self._cpu_threads = _load_config('cpu_threads', model_config, self.config_schema)
+    self._num_workers = _load_config('num_workers', model_config, self.config_schema)
+
+    self.transcribe_configs = \
+        {config: _load_config(config, model_config, self.config_schema)
+         for config in self.config_schema if not hasattr(self, f"_{config}")}
+
+    self.model = WhisperModel(model_size_or_path=self._model_size_or_path,
+                              device=self._device,
+                              device_index=self._device_index,
+                              compute_type=self._compute_type,
+                              cpu_threads=self._cpu_threads,
+                              num_workers=self._num_workers)
+
+
+ + + +
+ + + + + + + +
+ + + +
+ model_name + + + + instance-attribute + class-attribute + + +
+
model_name = 'guillaumekln/faster-whisper'
+
+ +
+
+ +
+ +
+ + + +
+ config_schema + + + + instance-attribute + class-attribute + + +
+
config_schema = {
+    "model_size_or_path": {
+        "type": list,
+        "description": 'Size of the model to use (e.g. "large-v2", "small", "tiny.en", etc.)or a path to a converted model directory. When a size is configured, the convertedmodel is downloaded from the Hugging Face Hub.',
+        "options": whisper.available_models(),
+        "default": "base",
+    },
+    "device": {
+        "type": list,
+        "description": 'Device to use for computation ("cpu", "cuda", "auto")',
+        "options": ["auto", "cpu", "cuda"],
+        "default": "auto",
+    },
+    "device_index": {
+        "type": int,
+        "description": "Device ID to use.The model can also be loaded on multiple GPUs by passing a list of IDs(e.g. [0, 1, 2, 3]). In that case, multiple transcriptions can run in parallelwhen transcribe() is called from multiple Python threads (see also num_workers).",
+        "options": None,
+        "default": 0,
+    },
+    "compute_type": {
+        "type": str,
+        "description": "Type to use for computation.See https://opennmt.net/CTranslate2/quantization.html.",
+        "options": None,
+        "default": "default",
+    },
+    "cpu_threads": {
+        "type": int,
+        "description": "Number of threads to use when running on CPU (4 by default).A non zero value overrides the OMP_NUM_THREADS environment variable.",
+        "options": None,
+        "default": 0,
+    },
+    "num_workers": {
+        "type": int,
+        "description": "When transcribe() is called from multiple Python threads,having multiple workers enables true parallelism when running the model(concurrent calls to self.model.generate() will run in parallel).This can improve the global throughput at the cost of increased memory usage.",
+        "options": None,
+        "default": 1,
+    },
+    "temperature": {
+        "type": Tuple,
+        "description": "Temperature for sampling. It can be a tuple of temperatures, which will be successively used upon failures according to either `compression_ratio_threshold` or `logprob_threshold`.",
+        "options": None,
+        "default": [0.0, 0.2, 0.4, 0.6, 0.8, 1.0],
+    },
+    "compression_ratio_threshold": {
+        "type": float,
+        "description": "If the gzip compression ratio is above this value, treat as failed",
+        "options": None,
+        "default": 2.4,
+    },
+    "log_prob_threshold": {
+        "type": float,
+        "description": "If the average log probability over sampled tokens is below this value, treat as failed",
+        "options": None,
+        "default": -1.0,
+    },
+    "no_speech_threshold": {
+        "type": float,
+        "description": "If the no_speech probability is higher than this value AND the average log probability over sampled tokens is below `logprob_threshold`, consider the segment as silent",
+        "options": None,
+        "default": 0.6,
+    },
+    "condition_on_previous_text": {
+        "type": bool,
+        "description": "if True, the previous output of the model is provided as a prompt for the next window; disabling may make the text inconsistent across windows, but the model becomes less prone to getting stuck in a failure loop, such as repetition looping or timestamps going out of sync.",
+        "options": None,
+        "default": True,
+    },
+    "task": {
+        "type": list,
+        "description": "whether to perform X->X 'transcribe' or X->English 'translate'",
+        "options": ["transcribe", "translate"],
+        "default": "transcribe",
+    },
+    "language": {
+        "type": str,
+        "description": "language that the audio is in; uses detected language if None",
+        "options": None,
+        "default": None,
+    },
+    "best_of": {
+        "type": int,
+        "description": "number of independent samples to collect, when t > 0",
+        "options": None,
+        "default": 5,
+    },
+    "beam_size": {
+        "type": int,
+        "description": "number of beams in beam search, when t == 0",
+        "options": None,
+        "default": 5,
+    },
+    "patience": {
+        "type": float,
+        "description": "patience in beam search (https://arxiv.org/abs/2204.05424)",
+        "options": None,
+        "default": 1.0,
+    },
+    "length_penalty": {
+        "type": float,
+        "description": "'alpha' in Google NMT, None defaults to length norm",
+        "options": None,
+        "default": 1.0,
+    },
+    "prefix": {
+        "type": str,
+        "description": "text or tokens to prefix the current context",
+        "options": None,
+        "default": None,
+    },
+    "suppress_blank": {
+        "type": bool,
+        "description": "this will suppress blank outputs",
+        "options": None,
+        "default": True,
+    },
+    "suppress_tokens": {
+        "type": Tuple,
+        "description": 'list of tokens ids (or comma-separated token ids) to suppress "-1" will suppress a set of symbols as defined in `tokenizer.non_speech_tokens()`',
+        "options": None,
+        "default": [-1],
+    },
+    "without_timestamps": {
+        "type": bool,
+        "description": "use <|notimestamps|> to sample text tokens only",
+        "options": None,
+        "default": False,
+    },
+    "max_initial_timestamp": {
+        "type": float,
+        "description": "the initial timestamp cannot be later than this",
+        "options": None,
+        "default": 1.0,
+    },
+    "initial_prompt": {
+        "type": str,
+        "description": "Optional text to provide as a prompt for the first window.",
+        "options": None,
+        "default": None,
+    },
+    "word_timestamps": {
+        "type": bool,
+        "description": "Extract word-level timestamps using the cross-attention patternand dynamic time warping, and include the timestamps for each word in each segment.",
+        "options": None,
+        "default": False,
+    },
+    "prepend_punctuations": {
+        "type": str,
+        "description": "If word_timestamps is True, merge these punctuation symbolswith the next word",
+        "options": None,
+        "default": "\"'“¿([{-",
+    },
+    "append_punctuations": {
+        "type": str,
+        "description": "If word_timestamps is True, merge these punctuation symbolswith the previous word",
+        "options": None,
+        "default": "\"'.。,,!!??::”)]}、",
+    },
+    "vad_filter": {
+        "type": bool,
+        "description": "If True, use the integrated Silero VAD model to filter out parts of the audio without speech.",
+        "options": None,
+        "default": False,
+    },
+    "vad_parameters": {
+        "type": dict,
+        "description": "Parameters for splitting long audios into speech chunks using silero VAD.",
+        "options": None,
+        "default": {
+            "threshold": 0.5,
+            "min_speech_duration_ms": 250,
+            "max_speech_duration_s": float("inf"),
+            "min_silence_duration_ms": 2000,
+            "window_size_samples": 1024,
+            "speech_pad_ms": 400,
+        },
+    },
+}
+
+ +
+
+ +
+ +
+ + + +
+ transcribe_configs + + + + instance-attribute + + +
+
transcribe_configs = {
+    config: _load_config(
+        config, model_config, self.config_schema
+    )
+    for config in self.config_schema
+    if not hasattr(self, f"_{config}")
+}
+
+ +
+
+ +
+ +
+ + + +
+ model + + + + instance-attribute + + +
+
model = WhisperModel(
+    model_size_or_path=self._model_size_or_path,
+    device=self._device,
+    device_index=self._device_index,
+    compute_type=self._compute_type,
+    cpu_threads=self._cpu_threads,
+    num_workers=self._num_workers,
+)
+
+ +
+
+ +
+ + + +
+ + + +
+ transcribe + + +
+
transcribe(media_file)
+
+ +
+ +
+ Source code in src/subsai/models/faster_whisper_model.py +
246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
def transcribe(self, media_file) -> str:
+    segments, info = self.model.transcribe(media_file, **self.transcribe_configs)
+    subs = SSAFile()
+    if self.transcribe_configs['word_timestamps']:  # word level timestamps
+        for segment in segments:
+            for word in segment.words:
+                event = SSAEvent(start=pysubs2.make_time(s=word.start), end=pysubs2.make_time(s=word.end))
+                event.plaintext = word.word.strip()
+                subs.append(event)
+    else:
+        for segment in segments:
+            event = SSAEvent(start=pysubs2.make_time(s=segment.start), end=pysubs2.make_time(s=segment.end))
+            event.plaintext = segment.text.strip()
+            subs.append(event)
+    return subs
+
+
+
+ +
+ + + +
+ +
+ +
+ + + + +
+ +
+ +
+ + +
+ +
+ +
+ +
+ + + +

+ subsai.configs + + +

+ +
+ +

Configurations file

+ + + +
+ + + + + + + +
+ + + +

+ AVAILABLE_MODELS + + + + module-attribute + + +

+
AVAILABLE_MODELS = {
+    "openai/whisper": {
+        "class": WhisperModel,
+        "description": "Whisper is a general-purpose speech recognition model. It is trained on a large dataset of diverse audio and is also a multi-task model that can perform multilingual speech recognition as well as speech translation and language identification.",
+        "url": "https://github.com/openai/whisper",
+        "config_schema": WhisperModel.config_schema,
+    },
+    "linto-ai/whisper-timestamped": {
+        "class": WhisperTimeStamped,
+        "description": "Multilingual Automatic Speech Recognition with word-level timestamps and confidence.",
+        "url": "https://github.com/linto-ai/whisper-timestamped",
+        "config_schema": WhisperTimeStamped.config_schema,
+    },
+    "ggerganov/whisper.cpp": {
+        "class": WhisperCppModel,
+        "description": "High-performance inference of OpenAI's Whisper automatic speech recognition (ASR) model\n* Plain C/C++ implementation without dependencies\n* Runs on the CPU\n",
+        "url": "https://github.com/ggerganov/whisper.cpp\nhttps://github.com/abdeladim-s/pywhispercpp",
+        "config_schema": WhisperCppModel.config_schema,
+    },
+    "guillaumekln/faster-whisper": {
+        "class": FasterWhisperModel,
+        "description": "**faster-whisper** is a reimplementation of OpenAI's Whisper model using [CTranslate2](https://github.com/OpenNMT/CTranslate2/), which is a fast inference engine for Transformer models.\nThis implementation is up to 4 times faster than [openai/whisper]( https://github.com/openai/whisper) for the same accuracy while using less memory. The efficiency can be further improved with 8-bit quantization on both CPU and GPU.",
+        "url": "https://github.com/guillaumekln/faster-whisper",
+        "config_schema": FasterWhisperModel.config_schema,
+    },
+}
+
+ +
+
+ +
+ +
+ + + +

+ BASIC_TOOLS_CONFIGS + + + + module-attribute + + +

+
BASIC_TOOLS_CONFIGS = {
+    "set time": {
+        "description": "Set time to a subtitle",
+        "config_schema": {
+            "h": {
+                "type": float,
+                "description": "hours: Integer or float values, may be positive or negative",
+                "options": None,
+                "default": 0,
+            },
+            "m": {
+                "type": float,
+                "description": "minutes: Integer or float values, may be positive or negative",
+                "options": None,
+                "default": 0,
+            },
+            "s": {
+                "type": float,
+                "description": "seconds: Integer or float values, may be positive or negative",
+                "options": None,
+                "default": 0,
+            },
+            "ms": {
+                "type": float,
+                "description": "milliseconds: Integer or float values, may be positive or negative",
+                "options": None,
+                "default": 0,
+            },
+        },
+    },
+    "shift": {
+        "description": "Shift all subtitles by constant time amount",
+        "config_schema": {
+            "h": {
+                "type": float,
+                "description": "hours: Integer or float values, may be positive or negative",
+                "options": None,
+                "default": 0,
+            },
+            "m": {
+                "type": float,
+                "description": "minutes: Integer or float values, may be positive or negative",
+                "options": None,
+                "default": 0,
+            },
+            "s": {
+                "type": float,
+                "description": "seconds: Integer or float values, may be positive or negative",
+                "options": None,
+                "default": 0,
+            },
+            "ms": {
+                "type": float,
+                "description": "milliseconds: Integer or float values, may be positive or negative",
+                "options": None,
+                "default": 0,
+            },
+            "frames": {
+                "type": int,
+                "description": "When specified, must be an integer number of frames",
+                "options": None,
+                "default": None,
+            },
+            "fps": {
+                "type": float,
+                "description": "When specified, must be a positive number.",
+                "options": None,
+                "default": None,
+            },
+        },
+    },
+}
+
+ +
+
+ +
+ +
+ + + +

+ ADVANCED_TOOLS_CONFIGS + + + + module-attribute + + +

+
ADVANCED_TOOLS_CONFIGS = {
+    "ffsubsync": {
+        "description": "Language-agnostic automatic synchronization of subtitles with video, so that subtitles are aligned to the correct starting point within the video.",
+        "url": "https://github.com/smacke/ffsubsync",
+        "config_schema": {
+            "vad": {
+                "type": list,
+                "description": "Which voice activity detector to use for speech extraction (if using video / audio as a reference",
+                "options": [
+                    "subs_then_webrtc",
+                    "webrtc",
+                    "subs_then_auditok",
+                    "auditok",
+                    "subs_then_silero",
+                    "silero",
+                ],
+                "default": DEFAULT_VAD,
+            },
+            "max-subtitle-seconds": {
+                "type": float,
+                "description": "Maximum duration for a subtitle to appear on-screen",
+                "options": None,
+                "default": DEFAULT_MAX_SUBTITLE_SECONDS,
+            },
+            "start-seconds": {
+                "type": int,
+                "description": "Start time for processing",
+                "options": None,
+                "default": DEFAULT_START_SECONDS,
+            },
+            "max-offset-seconds": {
+                "type": float,
+                "description": "The max allowed offset seconds for any subtitle segment",
+                "options": None,
+                "default": DEFAULT_MAX_OFFSET_SECONDS,
+            },
+            "apply-offset-seconds": {
+                "type": float,
+                "description": "Apply a predefined offset in seconds to all subtitle segments",
+                "options": None,
+                "default": DEFAULT_APPLY_OFFSET_SECONDS,
+            },
+            "suppress-output-if-offset-less-than": {
+                "type": float,
+                "description": "Apply a predefined offset in seconds to all subtitle segments",
+                "options": None,
+                "default": None,
+            },
+            "frame-rate": {
+                "type": int,
+                "description": "Frame rate for audio extraction",
+                "options": None,
+                "default": DEFAULT_FRAME_RATE,
+            },
+            "output-encoding": {
+                "type": str,
+                "description": 'What encoding to use for writing output subtitles (default=utf-8). Can indicate "same" to use same encoding as that of the input.',
+                "options": None,
+                "default": "utf-8",
+            },
+            "skip-infer-framerate-ratio": {
+                "type": bool,
+                "description": "If set, do not try to infer framerate ratio based on duration ratio.",
+                "options": None,
+                "default": False,
+            },
+            "no-fix-framerate": {
+                "type": bool,
+                "description": "If specified, subsync will not attempt to correct a framerate",
+                "options": None,
+                "default": False,
+            },
+            "serialize-speech": {
+                "type": bool,
+                "description": "If specified, serialize reference speech to a numpy array.",
+                "options": None,
+                "default": False,
+            },
+            "gss": {
+                "type": bool,
+                "description": "If specified, use golden-section search to try to findthe optimal framerate ratio between video and subtitles.",
+                "options": None,
+                "default": False,
+            },
+        },
+    },
+    "Translation": {
+        "description": "Translate to different languages using AI",
+        "url": "https://github.com/xhluca/dl-translate",
+        "config_schema": {
+            "model": {
+                "type": list,
+                "description": "The model",
+                "options": available_translation_models(),
+                "default": available_translation_models()[
+                    0
+                ],
+            },
+            "device": {
+                "type": list,
+                "description": '"cpu", "gpu" or "auto". If it\'s set to "auto", will try to select a GPU when available or else fall back to CPU',
+                "options": [
+                    "auto",
+                    get_available_devices(),
+                ],
+                "default": "auto",
+            },
+            "batch_size": {
+                "type": int,
+                "description": "The number of samples to load at once. If set to `None`, it will process everything at once\nA smaller value is preferred for `batch_size` if your (video) RAM is limited",
+                "options": None,
+                "default": 32,
+            },
+            "verbose": {
+                "type": bool,
+                "description": "Whether to display the progress bar for every batch processed.",
+                "options": None,
+                "default": True,
+            },
+        },
+    },
+}
+
+ +
+
+ +
+ + + + + +
+ +
+ +
+ + + + + + +
+
+ + + + +
+ + + +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/objects.inv b/objects.inv new file mode 100644 index 0000000000000000000000000000000000000000..af92355a935a7dadd9f60993e5c442d15292aceb GIT binary patch literal 148 zcmXAgF%E)26hw)oTw)S>Vl3$>>4+G6fkD23zvS;i(4*RV5jQbYyyWFghGrQ>cZhD( z;OvEs=EW(_#|*W(C%aIfS=%6CqDNVwtSekN(5M|_b^AXGobtFRt|MWb@1i{oZa^5t eV~~l6?A*K\ufe0f\ud83c\udf9e Subtitles generation tool (Web-UI + CLI + Python package) powered by OpenAI's Whisper and its variants \ud83c\udf9e\ufe0f

"},{"location":"#subsai.main","title":"subsai.main","text":"

SubsAI: Subtitles AI Subtitles generation tool powered by OpenAI's Whisper and its variants.

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/.

"},{"location":"#subsai.main.SubsAI","title":"SubsAI","text":"

Subs AI class

Example usage:

file = './assets/test1.mp4'\nsubs_ai = SubsAI()\nmodel = subs_ai.create_model('openai/whisper', {'model_type': 'base'})\nsubs = subs_ai.transcribe(file, model)\nsubs.save('test1.srt')\n

"},{"location":"#subsai.main.SubsAI.available_models","title":"available_models staticmethod","text":"
available_models()\n

Returns the supported models

Returns:

  • list \u2013

    list of available models

Source code in src/subsai/main.py
@staticmethod\ndef available_models() -> list:\n\"\"\"\n    Returns the supported models\n\n    :return: list of available models\n    \"\"\"\n    return list(AVAILABLE_MODELS.keys())\n
"},{"location":"#subsai.main.SubsAI.model_info","title":"model_info staticmethod","text":"
model_info(model)\n

Returns general infos about the model (brief description and url)

Parameters:

  • model (str) \u2013

    model name

Returns:

  • dict \u2013

    dict of infos

Source code in src/subsai/main.py
@staticmethod\ndef model_info(model: str) -> dict:\n\"\"\"\n    Returns general infos about the model (brief description and url)\n\n    :param model: model name\n\n    :return: dict of infos\n    \"\"\"\n    return {'description': AVAILABLE_MODELS[model]['description'],\n            'url': AVAILABLE_MODELS[model]['url']}\n
"},{"location":"#subsai.main.SubsAI.config_schema","title":"config_schema staticmethod","text":"
config_schema(model)\n

Returns the configs associated with a model

Parameters:

  • model (str) \u2013

    model name

Returns:

  • dict \u2013

    dict of configs

Source code in src/subsai/main.py
@staticmethod\ndef config_schema(model: str) -> dict:\n\"\"\"\n    Returns the configs associated with a model\n\n    :param model: model name\n\n    :return: dict of configs\n    \"\"\"\n    return AVAILABLE_MODELS[model]['config_schema']\n
"},{"location":"#subsai.main.SubsAI.create_model","title":"create_model staticmethod","text":"
create_model(model_name, model_config={})\n

Returns a model instance

Parameters:

  • model_name (str) \u2013

    the name of the model

  • model_config (dict) \u2013

    the configuration dict

Returns:

  • AbstractModel \u2013

    the model instance

Source code in src/subsai/main.py
@staticmethod\ndef create_model(model_name: str, model_config: dict = {}) -> AbstractModel:\n\"\"\"\n    Returns a model instance\n\n    :param model_name: the name of the model\n    :param model_config: the configuration dict\n\n    :return: the model instance\n    \"\"\"\n    return AVAILABLE_MODELS[model_name]['class'](model_config)\n
"},{"location":"#subsai.main.SubsAI.transcribe","title":"transcribe staticmethod","text":"
transcribe(media_file, model, model_config={})\n

Takes the model instance (created by :func:create_model) or the model name. Returns a :class:pysubs2.SSAFile https://pysubs2.readthedocs.io/en/latest/api-reference.html#ssafile-a-subtitle-file`_

Parameters:

  • media_file (str) \u2013

    path of the media file (video/audio)

  • model (Union[AbstractModel, str]) \u2013

    model instance or model name

  • model_config (dict) \u2013

    model configs' dict

Returns:

  • SSAFile \u2013

    SSAFile: list of subtitles

Source code in src/subsai/main.py
@staticmethod\ndef transcribe(media_file: str, model: Union[AbstractModel, str], model_config: dict = {}) -> SSAFile:\n\"\"\"\n    Takes the model instance (created by :func:`create_model`) or the model name.\n    Returns a :class:`pysubs2.SSAFile` <https://pysubs2.readthedocs.io/en/latest/api-reference.html#ssafile-a-subtitle-file>`_\n\n    :param media_file: path of the media file (video/audio)\n    :param model: model instance or model name\n    :param model_config: model configs' dict\n\n    :return: SSAFile: list of subtitles\n    \"\"\"\n    if type(model) == str:\n        stt_model = SubsAI.create_model(model, model_config)\n    else:\n        stt_model = model\n    media_file = str(pathlib.Path(media_file).resolve())\n    return stt_model.transcribe(media_file)\n
"},{"location":"#subsai.main.Tools","title":"Tools","text":"
Tools()\n

Some tools related to subtitles processing (ex: translation)

Source code in src/subsai/main.py
def __init__(self):\n    pass\n
"},{"location":"#subsai.main.Tools.available_translation_models","title":"available_translation_models staticmethod","text":"
available_translation_models()\n

Returns available translation models A simple link to :func:utils.available_translation_models for easy access

Returns:

  • list \u2013

    list of available models

Source code in src/subsai/main.py
@staticmethod\ndef available_translation_models() -> list:\n\"\"\"\n    Returns available translation models\n    A simple link to :func:`utils.available_translation_models` for easy access\n\n    :return: list of available models\n    \"\"\"\n\n    return available_translation_models()\n
"},{"location":"#subsai.main.Tools.available_translation_languages","title":"available_translation_languages staticmethod","text":"
available_translation_languages(model)\n

Returns the languages supported by the translation model

Parameters:

  • model (Union[str, TranslationModel]) \u2013

    the name of the model

Returns:

  • list \u2013

    list of available languages

Source code in src/subsai/main.py
@staticmethod\ndef available_translation_languages(model: Union[str, TranslationModel]) -> list:\n\"\"\"\n    Returns the languages supported by the translation model\n\n    :param model: the name of the model\n    :return: list of available languages\n    \"\"\"\n    if type(model) == str:\n        langs = Tools.create_translation_model(model).available_languages()\n    else:\n        langs = model.available_languages()\n    return langs\n
"},{"location":"#subsai.main.Tools.create_translation_model","title":"create_translation_model staticmethod","text":"
create_translation_model(model_name='m2m100')\n

Creates and returns a translation model instance.

Parameters:

  • model_name (str) \u2013

    name of the model. To get available models use :func:available_translation_models

Returns:

  • TranslationModel \u2013
Source code in src/subsai/main.py
@staticmethod\ndef create_translation_model(model_name: str = \"m2m100\") -> TranslationModel:\n\"\"\"\n    Creates and returns a translation model instance.\n\n    :param model_name: name of the model. To get available models use :func:`available_translation_models`\n    :return:\n    \"\"\"\n    mt = TranslationModel(model_name)\n    return mt\n
"},{"location":"#subsai.main.Tools.translate","title":"translate staticmethod","text":"
translate(\n    subs,\n    source_language,\n    target_language,\n    model=\"m2m100\",\n    translation_configs={},\n)\n

Translates a subtitles SSAFile object, what :func:SubsAI.transcribe is returning

Parameters:

  • subs (SSAFile) \u2013

    SSAFile object

  • source_language (str) \u2013

    the language of the subtitles

  • target_language (str) \u2013

    the target language

  • model (Union[str, TranslationModel]) \u2013

    the translation model, either an str or the model instance created by :func:create_translation_model

  • translation_configs (dict) \u2013

    dict of translation configs (see :attr:configs.ADVANCED_TOOLS_CONFIGS)

Returns:

  • SSAFile \u2013

    returns an SSAFile subtitles translated to the target language

Source code in src/subsai/main.py
@staticmethod\ndef translate(subs: SSAFile,\n              source_language: str,\n              target_language: str,\n              model: Union[str, TranslationModel] = \"m2m100\",\n              translation_configs: dict = {}) -> SSAFile:\n\"\"\"\n    Translates a subtitles `SSAFile` object, what :func:`SubsAI.transcribe` is returning\n\n    :param subs: `SSAFile` object\n    :param source_language: the language of the subtitles\n    :param target_language: the target language\n    :param model: the translation model, either an `str` or the model instance created by\n                    :func:`create_translation_model`\n    :param translation_configs: dict of translation configs (see :attr:`configs.ADVANCED_TOOLS_CONFIGS`)\n\n    :return: returns an `SSAFile` subtitles translated to the target language\n    \"\"\"\n    if type(model) == str:\n        translation_model = Tools.create_translation_model(model)\n    else:\n        translation_model = model\n\n    translated_subs = SSAFile()\n    for sub in subs:\n        translated_sub = sub.copy()\n        translated_sub.text = translation_model.translate(text=sub.text,\n                                                          source=source_language,\n                                                          target=target_language,\n                                                          batch_size=translation_configs[\n                                                              'batch_size'] if 'batch_size' in translation_configs else 32,\n                                                          verbose=translation_configs[\n                                                              'verbose'] if 'verbose' in translation_configs else False)\n        translated_subs.append(translated_sub)\n    return translated_subs\n
"},{"location":"#subsai.main.Tools.auto_sync","title":"auto_sync staticmethod","text":"
auto_sync(subs, media_file, **kwargs)\n

Uses (ffsubsync)[https://github.com/smacke/ffsubsync] to auto-sync subtitles to the media file

Parameters:

  • subs (SSAFile) \u2013

    SSAFile file

  • media_file (str) \u2013

    path of the media_file

  • kwargs \u2013

    configs to pass to ffsubsync (see :attr:configs.ADVANCED_TOOLS_CONFIGS)

Returns:

  • SSAFile \u2013

    SSAFile auto-synced

Source code in src/subsai/main.py
@staticmethod\ndef auto_sync(subs: SSAFile,\n              media_file: str,\n              **kwargs\n              ) -> SSAFile:\n\"\"\"\n    Uses (ffsubsync)[https://github.com/smacke/ffsubsync] to auto-sync subtitles to the media file\n\n    :param subs: `SSAFile` file\n    :param media_file: path of the media_file\n    :param kwargs: configs to pass to ffsubsync (see :attr:`configs.ADVANCED_TOOLS_CONFIGS`)\n\n    :return: `SSAFile` auto-synced\n    \"\"\"\n    parser = make_parser()\n    srtin_file = tempfile.NamedTemporaryFile(delete=False)\n    srtout_file = tempfile.NamedTemporaryFile(delete=False)\n    try:\n        srtin = srtin_file.name + '.ass'\n        srtout = srtout_file.name + '.srt'\n        subs.save(srtin)\n        cmd = [media_file,\n               '-i', srtin,\n               '-o', srtout]\n        for config_name in kwargs:\n            value = kwargs[config_name]\n            if value is None or value is False:\n                continue\n            elif type(value) == bool and value is True:\n                cmd.append(f'--{config_name}')\n            else:\n                cmd.append(f'--{config_name}')\n                cmd.append(f'{value}')\n        parsed_args = parser.parse_args(cmd)\n        retval = run(parsed_args)[\"retval\"]\n        synced_subs = pysubs2.load(srtout)\n        return synced_subs\n    finally:\n        srtin_file.close()\n        os.unlink(srtin_file.name)\n        srtout_file.close()\n        os.unlink(srtout_file.name)\n
"},{"location":"#subsai.models","title":"subsai.models","text":""},{"location":"#subsai.models.whisper_timestamped_model","title":"whisper_timestamped_model","text":"

whisper_timestamped

See linto-ai/whisper-timestamped

"},{"location":"#subsai.models.whisper_timestamped_model.WhisperTimeStamped","title":"WhisperTimeStamped","text":"
WhisperTimeStamped(model_config={})\n

Bases: AbstractModel

Source code in src/subsai/models/whisper_timestamped_model.py
def __init__(self, model_config={}):\n    super(WhisperTimeStamped, self).__init__(model_config=model_config,\n                                             model_name=self.model_name)\n    # config\n    self.model_type = _load_config('model_type', model_config, self.config_schema)\n    self.segment_type = _load_config('segment_type', model_config, self.config_schema)\n    self.device = _load_config('device', model_config, self.config_schema)\n    self.download_root = _load_config('download_root', model_config, self.config_schema)\n    self.in_memory = _load_config('in_memory', model_config, self.config_schema)\n\n    self.verbose = _load_config('verbose', model_config, self.config_schema)\n    self.temperature = _load_config('temperature', model_config, self.config_schema)\n    self.compression_ratio_threshold = _load_config('compression_ratio_threshold', model_config, self.config_schema)\n    self.logprob_threshold = _load_config('logprob_threshold', model_config, self.config_schema)\n    self.no_speech_threshold = _load_config('no_speech_threshold', model_config, self.config_schema)\n    self.condition_on_previous_text = _load_config('condition_on_previous_text', model_config, self.config_schema)\n\n    self.decode_options = \\\n        {config: _load_config(config, model_config, self.config_schema)\n         for config in self.config_schema if not hasattr(self, config)}\n\n    self.model = whisper_timestamped.load_model(name=self.model_type,\n                                                device=self.device,\n                                                download_root=self.download_root,\n                                                in_memory=self.in_memory)\n
"},{"location":"#subsai.models.whisper_timestamped_model.WhisperTimeStamped.model_name","title":"model_name instance-attribute class-attribute","text":"
model_name = 'linto-ai/whisper-timestamped'\n
"},{"location":"#subsai.models.whisper_timestamped_model.WhisperTimeStamped.config_schema","title":"config_schema instance-attribute class-attribute","text":"
config_schema = {\n    \"model_type\": {\n        \"type\": list,\n        \"description\": \"One of the official model names listed by `whisper.available_models()`, or path to a model checkpoint containing the model dimensions and the model state_dict.\",\n        \"options\": whisper_timestamped.available_models(),\n        \"default\": \"base\",\n    },\n    \"segment_type\": {\n        \"type\": list,\n        \"description\": \"Whisper_timestamps gives the ability to have word-level timestamps, Choose here between sentence-level and word-level\",\n        \"options\": [\"sentence\", \"word\"],\n        \"default\": \"sentence\",\n    },\n    \"device\": {\n        \"type\": list,\n        \"description\": \"The PyTorch device to put the model into\",\n        \"options\": [None, get_available_devices()],\n        \"default\": None,\n    },\n    \"download_root\": {\n        \"type\": str,\n        \"description\": \"Path to download the model files; by default, it uses '~/.cache/whisper'\",\n        \"options\": None,\n        \"default\": None,\n    },\n    \"in_memory\": {\n        \"type\": bool,\n        \"description\": \"whether to preload the model weights into host memory\",\n        \"options\": None,\n        \"default\": False,\n    },\n    \"verbose\": {\n        \"type\": bool,\n        \"description\": \"Whether to display the text being decoded to the console. If True, displays all the details,If False, displays minimal details. If None, does not display anything\",\n        \"options\": None,\n        \"default\": None,\n    },\n    \"temperature\": {\n        \"type\": Tuple,\n        \"description\": \"Temperature for sampling. It can be a tuple of temperatures, which will be successively used upon failures according to either `compression_ratio_threshold` or `logprob_threshold`.\",\n        \"options\": None,\n        \"default\": (0.0, 0.2, 0.4, 0.6, 0.8, 1.0),\n    },\n    \"compression_ratio_threshold\": {\n        \"type\": float,\n        \"description\": \"If the gzip compression ratio is above this value, treat as failed\",\n        \"options\": None,\n        \"default\": 2.4,\n    },\n    \"logprob_threshold\": {\n        \"type\": float,\n        \"description\": \"If the average log probability over sampled tokens is below this value, treat as failed\",\n        \"options\": None,\n        \"default\": -1.0,\n    },\n    \"no_speech_threshold\": {\n        \"type\": float,\n        \"description\": \"If the no_speech probability is higher than this value AND the average log probability over sampled tokens is below `logprob_threshold`, consider the segment as silent\",\n        \"options\": None,\n        \"default\": 0.6,\n    },\n    \"condition_on_previous_text\": {\n        \"type\": bool,\n        \"description\": \"if True, the previous output of the model is provided as a prompt for the next window; disabling may make the text inconsistent across windows, but the model becomes less prone to getting stuck in a failure loop, such as repetition looping or timestamps going out of sync.\",\n        \"options\": None,\n        \"default\": True,\n    },\n    \"task\": {\n        \"type\": list,\n        \"description\": \"whether to perform X->X 'transcribe' or X->English 'translate'\",\n        \"options\": [\"transcribe\", \"translate\"],\n        \"default\": \"transcribe\",\n    },\n    \"language\": {\n        \"type\": str,\n        \"description\": \"language that the audio is in; uses detected language if None\",\n        \"options\": None,\n        \"default\": None,\n    },\n    \"sample_len\": {\n        \"type\": int,\n        \"description\": \"maximum number of tokens to sample\",\n        \"options\": None,\n        \"default\": None,\n    },\n    \"best_of\": {\n        \"type\": int,\n        \"description\": \"number of independent samples to collect, when t > 0\",\n        \"options\": None,\n        \"default\": None,\n    },\n    \"beam_size\": {\n        \"type\": int,\n        \"description\": \"number of beams in beam search, when t == 0\",\n        \"options\": None,\n        \"default\": None,\n    },\n    \"patience\": {\n        \"type\": float,\n        \"description\": \"patience in beam search (https://arxiv.org/abs/2204.05424)\",\n        \"options\": None,\n        \"default\": None,\n    },\n    \"length_penalty\": {\n        \"type\": float,\n        \"description\": \"'alpha' in Google NMT, None defaults to length norm\",\n        \"options\": None,\n        \"default\": None,\n    },\n    \"suppress_tokens\": {\n        \"type\": str,\n        \"description\": 'list of tokens ids (or comma-separated token ids) to suppress \"-1\" will suppress a set of symbols as defined in `tokenizer.non_speech_tokens()`',\n        \"options\": None,\n        \"default\": \"-1\",\n    },\n    \"fp16\": {\n        \"type\": bool,\n        \"description\": \"use fp16 for most of the calculation\",\n        \"options\": None,\n        \"default\": True,\n    },\n    \"remove_punctuation_from_words\": {\n        \"type\": bool,\n        \"description\": \"If False, words will be glued with the next punctuation mark (if any).If True, there will be no punctuation mark in the `words[:]['text']` list.It only affects these strings; This has no influence on the computation of the word confidence, whatever the value of `include_punctuation_in_confidence` is.\",\n        \"options\": None,\n        \"default\": False,\n    },\n    \"refine_whisper_precision\": {\n        \"type\": float,\n        \"description\": \"How much can we refine Whisper segment positions, in seconds. Must be a multiple of 0.02.\",\n        \"options\": None,\n        \"default\": 0.5,\n    },\n    \"min_word_duration\": {\n        \"type\": float,\n        \"description\": \"Minimum duration of a word, in seconds. If a word is shorter than this, timestamps will be adjusted.\",\n        \"options\": None,\n        \"default\": 0.04,\n    },\n    \"plot_word_alignment\": {\n        \"type\": bool,\n        \"description\": \"Whether to plot the word alignment for each segment. matplotlib must be installed to use this option.\",\n        \"options\": None,\n        \"default\": False,\n    },\n    \"seed\": {\n        \"type\": int,\n        \"description\": \"Random seed to use for temperature sampling, for the sake of reproducibility.Choose None for unpredictable randomness\",\n        \"options\": None,\n        \"default\": 1234,\n    },\n    \"vad\": {\n        \"type\": bool,\n        \"description\": \"Whether to perform voice activity detection (VAD) on the audio file, to remove silent parts before transcribing with Whisper model. This should decrease hallucinations from the Whisper model.\",\n        \"options\": None,\n        \"default\": False,\n    },\n    \"detect_disfluencies\": {\n        \"type\": bool,\n        \"description\": 'Whether to detect disfluencies (i.e. hesitations, filler words, repetitions, corrections, etc.) that Whisper model might have omitted in the transcription. This should make the word timestamp prediction more accurate.And probable disfluencies will be marked as special words \"[*]\"',\n        \"options\": None,\n        \"default\": False,\n    },\n    \"trust_whisper_timestamps\": {\n        \"type\": bool,\n        \"description\": \"Whether to rely on Whisper's timestamps to get approximative first estimate of segment positions (up to refine_whisper_precision).\",\n        \"options\": None,\n        \"default\": True,\n    },\n    \"naive_approach\": {\n        \"type\": bool,\n        \"description\": \"Force the naive approach that consists in decoding twice the audio file, once to get the transcription and once with the decoded tokens to get the alignment. Note that this approach is used anyway when beam_size is not None and/or when the temperature is a list with more than one element.\",\n        \"options\": None,\n        \"default\": False,\n    },\n}\n
"},{"location":"#subsai.models.whisper_timestamped_model.WhisperTimeStamped.model_type","title":"model_type instance-attribute","text":"
model_type = _load_config(\n    \"model_type\", model_config, self.config_schema\n)\n
"},{"location":"#subsai.models.whisper_timestamped_model.WhisperTimeStamped.segment_type","title":"segment_type instance-attribute","text":"
segment_type = _load_config(\n    \"segment_type\", model_config, self.config_schema\n)\n
"},{"location":"#subsai.models.whisper_timestamped_model.WhisperTimeStamped.device","title":"device instance-attribute","text":"
device = _load_config(\n    \"device\", model_config, self.config_schema\n)\n
"},{"location":"#subsai.models.whisper_timestamped_model.WhisperTimeStamped.download_root","title":"download_root instance-attribute","text":"
download_root = _load_config(\n    \"download_root\", model_config, self.config_schema\n)\n
"},{"location":"#subsai.models.whisper_timestamped_model.WhisperTimeStamped.in_memory","title":"in_memory instance-attribute","text":"
in_memory = _load_config(\n    \"in_memory\", model_config, self.config_schema\n)\n
"},{"location":"#subsai.models.whisper_timestamped_model.WhisperTimeStamped.verbose","title":"verbose instance-attribute","text":"
verbose = _load_config(\n    \"verbose\", model_config, self.config_schema\n)\n
"},{"location":"#subsai.models.whisper_timestamped_model.WhisperTimeStamped.temperature","title":"temperature instance-attribute","text":"
temperature = _load_config(\n    \"temperature\", model_config, self.config_schema\n)\n
"},{"location":"#subsai.models.whisper_timestamped_model.WhisperTimeStamped.compression_ratio_threshold","title":"compression_ratio_threshold instance-attribute","text":"
compression_ratio_threshold = _load_config(\n    \"compression_ratio_threshold\",\n    model_config,\n    self.config_schema,\n)\n
"},{"location":"#subsai.models.whisper_timestamped_model.WhisperTimeStamped.logprob_threshold","title":"logprob_threshold instance-attribute","text":"
logprob_threshold = _load_config(\n    \"logprob_threshold\", model_config, self.config_schema\n)\n
"},{"location":"#subsai.models.whisper_timestamped_model.WhisperTimeStamped.no_speech_threshold","title":"no_speech_threshold instance-attribute","text":"
no_speech_threshold = _load_config(\n    \"no_speech_threshold\", model_config, self.config_schema\n)\n
"},{"location":"#subsai.models.whisper_timestamped_model.WhisperTimeStamped.condition_on_previous_text","title":"condition_on_previous_text instance-attribute","text":"
condition_on_previous_text = _load_config(\n    \"condition_on_previous_text\",\n    model_config,\n    self.config_schema,\n)\n
"},{"location":"#subsai.models.whisper_timestamped_model.WhisperTimeStamped.decode_options","title":"decode_options instance-attribute","text":"
decode_options = {\n    config: _load_config(\n        config, model_config, self.config_schema\n    )\n    for config in self.config_schema\n    if not hasattr(self, config)\n}\n
"},{"location":"#subsai.models.whisper_timestamped_model.WhisperTimeStamped.model","title":"model instance-attribute","text":"
model = whisper_timestamped.load_model(\n    name=self.model_type,\n    device=self.device,\n    download_root=self.download_root,\n    in_memory=self.in_memory,\n)\n
"},{"location":"#subsai.models.whisper_timestamped_model.WhisperTimeStamped.transcribe","title":"transcribe","text":"
transcribe(media_file)\n
Source code in src/subsai/models/whisper_timestamped_model.py
def transcribe(self, media_file) -> str:\n    audio = whisper_timestamped.load_audio(media_file)\n    results = whisper_timestamped.transcribe(self.model, audio,\n                                             verbose=self.verbose,\n                                             temperature=self.temperature,\n                                             compression_ratio_threshold=self.compression_ratio_threshold,\n                                             logprob_threshold=self.logprob_threshold,\n                                             no_speech_threshold=self.no_speech_threshold,\n                                             condition_on_previous_text=self.condition_on_previous_text,\n                                             **self.decode_options\n                                             )\n    subs = SSAFile()\n    if self.segment_type == 'word':  # word level timestamps\n        for segment in results['segments']:\n            for word in segment['words']:\n                event = SSAEvent(start=pysubs2.make_time(s=word[\"start\"]), end=pysubs2.make_time(s=word[\"end\"]))\n                event.plaintext = word[\"text\"].strip()\n                subs.append(event)\n    elif self.segment_type == 'sentence':\n        for segment in results['segments']:\n            event = SSAEvent(start=pysubs2.make_time(s=segment[\"start\"]), end=pysubs2.make_time(s=segment[\"end\"]))\n            event.plaintext = segment[\"text\"].strip()\n            subs.append(event)\n    else:\n        raise Exception(f'Unknown `segment_type` value, it should be one of the following: '\n                        f' {self.config_schema[\"segment_type\"][\"options\"]}')\n    return subs\n
"},{"location":"#subsai.models.abstract_model","title":"abstract_model","text":"

API that the transcription models should follow

"},{"location":"#subsai.models.abstract_model.AbstractModel","title":"AbstractModel","text":"
AbstractModel(model_name=None, model_config={})\n

Bases: ABC

Abstract Model class

Source code in src/subsai/models/abstract_model.py
def __init__(self, model_name=None, model_config={}):\n    self.model_name = model_name\n    self.model_config = model_config\n
"},{"location":"#subsai.models.abstract_model.AbstractModel.model_name","title":"model_name instance-attribute","text":"
model_name = model_name\n
"},{"location":"#subsai.models.abstract_model.AbstractModel.model_config","title":"model_config instance-attribute","text":"
model_config = model_config\n
"},{"location":"#subsai.models.abstract_model.AbstractModel.transcribe","title":"transcribe abstractmethod","text":"
transcribe(media_file)\n

Transcribe the media_file to subtitles.

example use case from pysubs2.whisper:

.. code-block:: python :linenos:

subs = SSAFile() for segment in segments: event = SSAEvent(start=make_time(s=segment[\"start\"]), end=make_time(s=segment[\"end\"])) event.plaintext = segment[\"text\"].strip() subs.append(event)

Parameters:

  • media_file \u2013

    Path of the media file

Returns:

  • SSAFile \u2013

    Collection of SSAEvent(s) (see :mod:pysubs2.ssaevent)

Source code in src/subsai/models/abstract_model.py
@abstractmethod\ndef transcribe(self, media_file) -> SSAFile:\n\"\"\"\n    Transcribe the `media_file` to subtitles.\n\n    example use case from pysubs2.whisper:\n\n    .. code-block:: python\n        :linenos:\n\n    subs = SSAFile()\n    for segment in segments:\n        event = SSAEvent(start=make_time(s=segment[\"start\"]), end=make_time(s=segment[\"end\"]))\n        event.plaintext = segment[\"text\"].strip()\n        subs.append(event)\n\n    :param media_file: Path of the media file\n    :return: Collection of SSAEvent(s) (see :mod:`pysubs2.ssaevent`)\n    \"\"\"\n    pass\n
"},{"location":"#subsai.models.whisper_model","title":"whisper_model","text":"

Whisper Model

See openai/whisper

"},{"location":"#subsai.models.whisper_model.WhisperModel","title":"WhisperModel","text":"
WhisperModel(model_config)\n

Bases: AbstractModel

Source code in src/subsai/models/whisper_model.py
def __init__(self, model_config):\n    super(WhisperModel, self).__init__(model_config=model_config,\n                                       model_name=self.model_name)\n    # config\n    self.model_type = _load_config('model_type', model_config, self.config_schema)\n    self.device = _load_config('device', model_config, self.config_schema)\n    self.download_root = _load_config('download_root', model_config, self.config_schema)\n    self.in_memory = _load_config('in_memory', model_config, self.config_schema)\n\n    self.verbose = _load_config('verbose', model_config, self.config_schema)\n    self.temperature = _load_config('temperature', model_config, self.config_schema)\n    self.compression_ratio_threshold = _load_config('compression_ratio_threshold', model_config, self.config_schema)\n    self.logprob_threshold = _load_config('logprob_threshold', model_config, self.config_schema)\n    self.no_speech_threshold = _load_config('no_speech_threshold', model_config, self.config_schema)\n    self.condition_on_previous_text = _load_config('condition_on_previous_text', model_config, self.config_schema)\n\n    self.decode_options = \\\n        {config: _load_config(config, model_config, self.config_schema)\n         for config in self.config_schema if not hasattr(self, config)}\n\n    self.model = whisper.load_model(name=self.model_type,\n                                    device=self.device,\n                                    download_root=self.download_root,\n                                    in_memory=self.in_memory)\n
"},{"location":"#subsai.models.whisper_model.WhisperModel.model_name","title":"model_name instance-attribute class-attribute","text":"
model_name = 'openai/whisper'\n
"},{"location":"#subsai.models.whisper_model.WhisperModel.config_schema","title":"config_schema instance-attribute class-attribute","text":"
config_schema = {\n    \"model_type\": {\n        \"type\": list,\n        \"description\": \"One of the official model names listed by `whisper.available_models()`, or path to a model checkpoint containing the model dimensions and the model state_dict.\",\n        \"options\": whisper.available_models(),\n        \"default\": \"base\",\n    },\n    \"device\": {\n        \"type\": list,\n        \"description\": \"The PyTorch device to put the model into\",\n        \"options\": [None, get_available_devices()],\n        \"default\": None,\n    },\n    \"download_root\": {\n        \"type\": str,\n        \"description\": \"Path to download the model files; by default, it uses '~/.cache/whisper'\",\n        \"options\": None,\n        \"default\": None,\n    },\n    \"in_memory\": {\n        \"type\": bool,\n        \"description\": \"whether to preload the model weights into host memory\",\n        \"options\": None,\n        \"default\": False,\n    },\n    \"verbose\": {\n        \"type\": bool,\n        \"description\": \"Whether to display the text being decoded to the console. If True, displays all the details,If False, displays minimal details. If None, does not display anything\",\n        \"options\": None,\n        \"default\": None,\n    },\n    \"temperature\": {\n        \"type\": Tuple,\n        \"description\": \"Temperature for sampling. It can be a tuple of temperatures, which will be successively used upon failures according to either `compression_ratio_threshold` or `logprob_threshold`.\",\n        \"options\": None,\n        \"default\": (0.0, 0.2, 0.4, 0.6, 0.8, 1.0),\n    },\n    \"compression_ratio_threshold\": {\n        \"type\": float,\n        \"description\": \"If the gzip compression ratio is above this value, treat as failed\",\n        \"options\": None,\n        \"default\": 2.4,\n    },\n    \"logprob_threshold\": {\n        \"type\": float,\n        \"description\": \"If the average log probability over sampled tokens is below this value, treat as failed\",\n        \"options\": None,\n        \"default\": -1.0,\n    },\n    \"no_speech_threshold\": {\n        \"type\": float,\n        \"description\": \"If the no_speech probability is higher than this value AND the average log probability over sampled tokens is below `logprob_threshold`, consider the segment as silent\",\n        \"options\": None,\n        \"default\": 0.6,\n    },\n    \"condition_on_previous_text\": {\n        \"type\": bool,\n        \"description\": \"if True, the previous output of the model is provided as a prompt for the next window; disabling may make the text inconsistent across windows, but the model becomes less prone to getting stuck in a failure loop, such as repetition looping or timestamps going out of sync.\",\n        \"options\": None,\n        \"default\": True,\n    },\n    \"task\": {\n        \"type\": list,\n        \"description\": \"whether to perform X->X 'transcribe' or X->English 'translate'\",\n        \"options\": [\"transcribe\", \"translate\"],\n        \"default\": \"transcribe\",\n    },\n    \"language\": {\n        \"type\": str,\n        \"description\": \"language that the audio is in; uses detected language if None\",\n        \"options\": None,\n        \"default\": None,\n    },\n    \"sample_len\": {\n        \"type\": int,\n        \"description\": \"maximum number of tokens to sample\",\n        \"options\": None,\n        \"default\": None,\n    },\n    \"best_of\": {\n        \"type\": int,\n        \"description\": \"number of independent samples to collect, when t > 0\",\n        \"options\": None,\n        \"default\": None,\n    },\n    \"beam_size\": {\n        \"type\": int,\n        \"description\": \"number of beams in beam search, when t == 0\",\n        \"options\": None,\n        \"default\": None,\n    },\n    \"patience\": {\n        \"type\": float,\n        \"description\": \"patience in beam search (https://arxiv.org/abs/2204.05424)\",\n        \"options\": None,\n        \"default\": None,\n    },\n    \"length_penalty\": {\n        \"type\": float,\n        \"description\": \"'alpha' in Google NMT, None defaults to length norm\",\n        \"options\": None,\n        \"default\": None,\n    },\n    \"prompt\": {\n        \"type\": str,\n        \"description\": \"text or tokens for the previous context\",\n        \"options\": None,\n        \"default\": None,\n    },\n    \"prefix\": {\n        \"type\": str,\n        \"description\": \"text or tokens to prefix the current context\",\n        \"options\": None,\n        \"default\": None,\n    },\n    \"suppress_blank\": {\n        \"type\": bool,\n        \"description\": \"this will suppress blank outputs\",\n        \"options\": None,\n        \"default\": True,\n    },\n    \"suppress_tokens\": {\n        \"type\": str,\n        \"description\": 'list of tokens ids (or comma-separated token ids) to suppress \"-1\" will suppress a set of symbols as defined in `tokenizer.non_speech_tokens()`',\n        \"options\": None,\n        \"default\": \"-1\",\n    },\n    \"without_timestamps\": {\n        \"type\": bool,\n        \"description\": \"use <|notimestamps|> to sample text tokens only\",\n        \"options\": None,\n        \"default\": False,\n    },\n    \"max_initial_timestamp\": {\n        \"type\": float,\n        \"description\": \"the initial timestamp cannot be later than this\",\n        \"options\": None,\n        \"default\": 1.0,\n    },\n    \"fp16\": {\n        \"type\": bool,\n        \"description\": \"use fp16 for most of the calculation\",\n        \"options\": None,\n        \"default\": True,\n    },\n}\n
"},{"location":"#subsai.models.whisper_model.WhisperModel.model_type","title":"model_type instance-attribute","text":"
model_type = _load_config(\n    \"model_type\", model_config, self.config_schema\n)\n
"},{"location":"#subsai.models.whisper_model.WhisperModel.device","title":"device instance-attribute","text":"
device = _load_config(\n    \"device\", model_config, self.config_schema\n)\n
"},{"location":"#subsai.models.whisper_model.WhisperModel.download_root","title":"download_root instance-attribute","text":"
download_root = _load_config(\n    \"download_root\", model_config, self.config_schema\n)\n
"},{"location":"#subsai.models.whisper_model.WhisperModel.in_memory","title":"in_memory instance-attribute","text":"
in_memory = _load_config(\n    \"in_memory\", model_config, self.config_schema\n)\n
"},{"location":"#subsai.models.whisper_model.WhisperModel.verbose","title":"verbose instance-attribute","text":"
verbose = _load_config(\n    \"verbose\", model_config, self.config_schema\n)\n
"},{"location":"#subsai.models.whisper_model.WhisperModel.temperature","title":"temperature instance-attribute","text":"
temperature = _load_config(\n    \"temperature\", model_config, self.config_schema\n)\n
"},{"location":"#subsai.models.whisper_model.WhisperModel.compression_ratio_threshold","title":"compression_ratio_threshold instance-attribute","text":"
compression_ratio_threshold = _load_config(\n    \"compression_ratio_threshold\",\n    model_config,\n    self.config_schema,\n)\n
"},{"location":"#subsai.models.whisper_model.WhisperModel.logprob_threshold","title":"logprob_threshold instance-attribute","text":"
logprob_threshold = _load_config(\n    \"logprob_threshold\", model_config, self.config_schema\n)\n
"},{"location":"#subsai.models.whisper_model.WhisperModel.no_speech_threshold","title":"no_speech_threshold instance-attribute","text":"
no_speech_threshold = _load_config(\n    \"no_speech_threshold\", model_config, self.config_schema\n)\n
"},{"location":"#subsai.models.whisper_model.WhisperModel.condition_on_previous_text","title":"condition_on_previous_text instance-attribute","text":"
condition_on_previous_text = _load_config(\n    \"condition_on_previous_text\",\n    model_config,\n    self.config_schema,\n)\n
"},{"location":"#subsai.models.whisper_model.WhisperModel.decode_options","title":"decode_options instance-attribute","text":"
decode_options = {\n    config: _load_config(\n        config, model_config, self.config_schema\n    )\n    for config in self.config_schema\n    if not hasattr(self, config)\n}\n
"},{"location":"#subsai.models.whisper_model.WhisperModel.model","title":"model instance-attribute","text":"
model = whisper.load_model(\n    name=self.model_type,\n    device=self.device,\n    download_root=self.download_root,\n    in_memory=self.in_memory,\n)\n
"},{"location":"#subsai.models.whisper_model.WhisperModel.transcribe","title":"transcribe","text":"
transcribe(media_file)\n
Source code in src/subsai/models/whisper_model.py
def transcribe(self, media_file) -> str:\n    audio = whisper.load_audio(media_file)\n    result = self.model.transcribe(audio, verbose=self.verbose,\n                                   temperature=self.temperature,\n                                   compression_ratio_threshold=self.compression_ratio_threshold,\n                                   logprob_threshold=self.logprob_threshold,\n                                   no_speech_threshold=self.no_speech_threshold,\n                                   condition_on_previous_text=self.condition_on_previous_text,\n                                   **self.decode_options)\n    subs = pysubs2.load_from_whisper(result)\n    return subs\n
"},{"location":"#subsai.models.whispercpp_model","title":"whispercpp_model","text":"

Whisper.cpp Model

See whisper.cpp, See pywhispercpp

"},{"location":"#subsai.models.whispercpp_model.WhisperCppModel","title":"WhisperCppModel","text":"
WhisperCppModel(model_config)\n

Bases: AbstractModel

Source code in src/subsai/models/whispercpp_model.py
def __init__(self, model_config):\n    super(WhisperCppModel, self).__init__(model_config=model_config,\n                                       model_name=self.model_name)\n    # config\n    self.model_type = _load_config('model_type', model_config, self.config_schema)\n\n    self.params = {}\n    for config in self.config_schema:\n        if not hasattr(self, config):\n            config_value = _load_config(config, model_config, self.config_schema)\n            if config_value is None:\n                continue\n            self.params[config] = config_value\n\n    self.model = Model(model=self.model_type, **self.params)\n
"},{"location":"#subsai.models.whispercpp_model.WhisperCppModel.model_name","title":"model_name instance-attribute class-attribute","text":"
model_name = 'ggerganov/whisper.cpp'\n
"},{"location":"#subsai.models.whispercpp_model.WhisperCppModel.config_schema","title":"config_schema instance-attribute class-attribute","text":"
config_schema = {\n    \"model_type\": {\n        \"type\": list,\n        \"description\": \"Available whisper.cpp models\",\n        \"options\": AVAILABLE_MODELS,\n        \"default\": \"base\",\n    },\n    \"n_threads\": {\n        \"type\": int,\n        \"description\": \"Number of threads to allocate for the inferencedefault to min(4, available hardware_concurrency)\",\n        \"options\": None,\n        \"default\": 4,\n    },\n    \"n_max_text_ctx\": {\n        \"type\": int,\n        \"description\": \"max tokens to use from past text as prompt for the decoder\",\n        \"options\": None,\n        \"default\": 16384,\n    },\n    \"offset_ms\": {\n        \"type\": int,\n        \"description\": \"start offset in ms\",\n        \"options\": None,\n        \"default\": 0,\n    },\n    \"duration_ms\": {\n        \"type\": int,\n        \"description\": \"audio duration to process in ms\",\n        \"options\": None,\n        \"default\": 0,\n    },\n    \"translate\": {\n        \"type\": bool,\n        \"description\": \"whether to translate the audio to English\",\n        \"options\": None,\n        \"default\": False,\n    },\n    \"no_context\": {\n        \"type\": bool,\n        \"description\": \"do not use past transcription (if any) as initial prompt for the decoder\",\n        \"options\": None,\n        \"default\": False,\n    },\n    \"single_segment\": {\n        \"type\": bool,\n        \"description\": \"force single segment output (useful for streaming)\",\n        \"options\": None,\n        \"default\": False,\n    },\n    \"print_special\": {\n        \"type\": bool,\n        \"description\": \"print special tokens (e.g. <SOT>, <EOT>, <BEG>, etc.)\",\n        \"options\": None,\n        \"default\": False,\n    },\n    \"print_progress\": {\n        \"type\": bool,\n        \"description\": \"print progress information\",\n        \"options\": None,\n        \"default\": True,\n    },\n    \"print_realtime\": {\n        \"type\": bool,\n        \"description\": \"print results from within whisper.cpp (avoid it, use callback instead)\",\n        \"options\": None,\n        \"default\": False,\n    },\n    \"print_timestamps\": {\n        \"type\": bool,\n        \"description\": \"print timestamps for each text segment when printing realtime\",\n        \"options\": None,\n        \"default\": True,\n    },\n    \"token_timestamps\": {\n        \"type\": bool,\n        \"description\": \"enable token-level timestamps\",\n        \"options\": None,\n        \"default\": False,\n    },\n    \"thold_pt\": {\n        \"type\": float,\n        \"description\": \"timestamp token probability threshold (~0.01)\",\n        \"options\": None,\n        \"default\": 0.01,\n    },\n    \"thold_ptsum\": {\n        \"type\": float,\n        \"description\": \"timestamp token sum probability threshold (~0.01)\",\n        \"options\": None,\n        \"default\": 0.01,\n    },\n    \"max_len\": {\n        \"type\": int,\n        \"description\": \"max segment length in characters\",\n        \"options\": None,\n        \"default\": 0,\n    },\n    \"split_on_word\": {\n        \"type\": bool,\n        \"description\": \"split on word rather than on token (when used with max_len)\",\n        \"options\": None,\n        \"default\": False,\n    },\n    \"max_tokens\": {\n        \"type\": int,\n        \"description\": \"max tokens per segment (0 = no limit)\",\n        \"options\": None,\n        \"default\": 0,\n    },\n    \"speed_up\": {\n        \"type\": bool,\n        \"description\": \"speed-up the audio by 2x using Phase Vocoder\",\n        \"options\": None,\n        \"default\": False,\n    },\n    \"audio_ctx\": {\n        \"type\": int,\n        \"description\": \"overwrite the audio context size (0 = use default)\",\n        \"options\": None,\n        \"default\": 0,\n    },\n    \"prompt_n_tokens\": {\n        \"type\": int,\n        \"description\": \"tokens to provide to the whisper decoder as initial prompt\",\n        \"options\": None,\n        \"default\": 0,\n    },\n    \"language\": {\n        \"type\": str,\n        \"description\": 'for auto-detection, set to None, \"\" or \"auto\"',\n        \"options\": None,\n        \"default\": \"en\",\n    },\n    \"suppress_blank\": {\n        \"type\": bool,\n        \"description\": \"common decoding parameters\",\n        \"options\": None,\n        \"default\": True,\n    },\n    \"suppress_non_speech_tokens\": {\n        \"type\": bool,\n        \"description\": \"common decoding parameters\",\n        \"options\": None,\n        \"default\": False,\n    },\n    \"temperature\": {\n        \"type\": float,\n        \"description\": \"initial decoding temperature\",\n        \"options\": None,\n        \"default\": 0.0,\n    },\n    \"max_initial_ts\": {\n        \"type\": float,\n        \"description\": \"max_initial_ts\",\n        \"options\": None,\n        \"default\": 1.0,\n    },\n    \"length_penalty\": {\n        \"type\": float,\n        \"description\": \"length_penalty\",\n        \"options\": None,\n        \"default\": -1.0,\n    },\n    \"temperature_inc\": {\n        \"type\": float,\n        \"description\": \"temperature_inc\",\n        \"options\": None,\n        \"default\": 0.2,\n    },\n    \"entropy_thold\": {\n        \"type\": float,\n        \"description\": 'similar to OpenAI\\'s \"compression_ratio_threshold\"',\n        \"options\": None,\n        \"default\": 2.4,\n    },\n    \"logprob_thold\": {\n        \"type\": float,\n        \"description\": \"logprob_thold\",\n        \"options\": None,\n        \"default\": -1.0,\n    },\n    \"no_speech_thold\": {\n        \"type\": float,\n        \"description\": \"no_speech_thold\",\n        \"options\": None,\n        \"default\": 0.6,\n    },\n    \"greedy\": {\n        \"type\": dict,\n        \"description\": \"greedy\",\n        \"options\": None,\n        \"default\": {\"best_of\": -1},\n    },\n    \"beam_search\": {\n        \"type\": dict,\n        \"description\": \"beam_search\",\n        \"options\": None,\n        \"default\": {\"beam_size\": -1, \"patience\": -1.0},\n    },\n}\n
"},{"location":"#subsai.models.whispercpp_model.WhisperCppModel.model_type","title":"model_type instance-attribute","text":"
model_type = _load_config(\n    \"model_type\", model_config, self.config_schema\n)\n
"},{"location":"#subsai.models.whispercpp_model.WhisperCppModel.params","title":"params instance-attribute","text":"
params = {}\n
"},{"location":"#subsai.models.whispercpp_model.WhisperCppModel.model","title":"model instance-attribute","text":"
model = Model(model=self.model_type, None=self.params)\n
"},{"location":"#subsai.models.whispercpp_model.WhisperCppModel.transcribe","title":"transcribe","text":"
transcribe(media_file)\n
Source code in src/subsai/models/whispercpp_model.py
def transcribe(self, media_file) -> str:\n    segments = self.model.transcribe(media=media_file)\n    subs = SSAFile()\n    for seg in segments:\n        event = SSAEvent(start=seg.t0*10, end=seg.t1*10)\n        event.plaintext = seg.text.strip()\n        subs.append(event)\n    return subs\n
"},{"location":"#subsai.models.faster_whisper_model","title":"faster_whisper_model","text":"

Faster Whisper Model

See guillaumekln/faster-whisper

"},{"location":"#subsai.models.faster_whisper_model.FasterWhisperModel","title":"FasterWhisperModel","text":"
FasterWhisperModel(model_config)\n

Bases: AbstractModel

Source code in src/subsai/models/faster_whisper_model.py
def __init__(self, model_config):\n    super(FasterWhisperModel, self).__init__(model_config=model_config,\n                                       model_name=self.model_name)\n    # config\n    self._model_size_or_path = _load_config('model_size_or_path', model_config, self.config_schema)\n    self._device = _load_config('device', model_config, self.config_schema)\n    self._device_index = _load_config('device_index', model_config, self.config_schema)\n    self._compute_type = _load_config('compute_type', model_config, self.config_schema)\n    self._cpu_threads = _load_config('cpu_threads', model_config, self.config_schema)\n    self._num_workers = _load_config('num_workers', model_config, self.config_schema)\n\n    self.transcribe_configs = \\\n        {config: _load_config(config, model_config, self.config_schema)\n         for config in self.config_schema if not hasattr(self, f\"_{config}\")}\n\n    self.model = WhisperModel(model_size_or_path=self._model_size_or_path,\n                              device=self._device,\n                              device_index=self._device_index,\n                              compute_type=self._compute_type,\n                              cpu_threads=self._cpu_threads,\n                              num_workers=self._num_workers)\n
"},{"location":"#subsai.models.faster_whisper_model.FasterWhisperModel.model_name","title":"model_name instance-attribute class-attribute","text":"
model_name = 'guillaumekln/faster-whisper'\n
"},{"location":"#subsai.models.faster_whisper_model.FasterWhisperModel.config_schema","title":"config_schema instance-attribute class-attribute","text":"
config_schema = {\n    \"model_size_or_path\": {\n        \"type\": list,\n        \"description\": 'Size of the model to use (e.g. \"large-v2\", \"small\", \"tiny.en\", etc.)or a path to a converted model directory. When a size is configured, the convertedmodel is downloaded from the Hugging Face Hub.',\n        \"options\": whisper.available_models(),\n        \"default\": \"base\",\n    },\n    \"device\": {\n        \"type\": list,\n        \"description\": 'Device to use for computation (\"cpu\", \"cuda\", \"auto\")',\n        \"options\": [\"auto\", \"cpu\", \"cuda\"],\n        \"default\": \"auto\",\n    },\n    \"device_index\": {\n        \"type\": int,\n        \"description\": \"Device ID to use.The model can also be loaded on multiple GPUs by passing a list of IDs(e.g. [0, 1, 2, 3]). In that case, multiple transcriptions can run in parallelwhen transcribe() is called from multiple Python threads (see also num_workers).\",\n        \"options\": None,\n        \"default\": 0,\n    },\n    \"compute_type\": {\n        \"type\": str,\n        \"description\": \"Type to use for computation.See https://opennmt.net/CTranslate2/quantization.html.\",\n        \"options\": None,\n        \"default\": \"default\",\n    },\n    \"cpu_threads\": {\n        \"type\": int,\n        \"description\": \"Number of threads to use when running on CPU (4 by default).A non zero value overrides the OMP_NUM_THREADS environment variable.\",\n        \"options\": None,\n        \"default\": 0,\n    },\n    \"num_workers\": {\n        \"type\": int,\n        \"description\": \"When transcribe() is called from multiple Python threads,having multiple workers enables true parallelism when running the model(concurrent calls to self.model.generate() will run in parallel).This can improve the global throughput at the cost of increased memory usage.\",\n        \"options\": None,\n        \"default\": 1,\n    },\n    \"temperature\": {\n        \"type\": Tuple,\n        \"description\": \"Temperature for sampling. It can be a tuple of temperatures, which will be successively used upon failures according to either `compression_ratio_threshold` or `logprob_threshold`.\",\n        \"options\": None,\n        \"default\": [0.0, 0.2, 0.4, 0.6, 0.8, 1.0],\n    },\n    \"compression_ratio_threshold\": {\n        \"type\": float,\n        \"description\": \"If the gzip compression ratio is above this value, treat as failed\",\n        \"options\": None,\n        \"default\": 2.4,\n    },\n    \"log_prob_threshold\": {\n        \"type\": float,\n        \"description\": \"If the average log probability over sampled tokens is below this value, treat as failed\",\n        \"options\": None,\n        \"default\": -1.0,\n    },\n    \"no_speech_threshold\": {\n        \"type\": float,\n        \"description\": \"If the no_speech probability is higher than this value AND the average log probability over sampled tokens is below `logprob_threshold`, consider the segment as silent\",\n        \"options\": None,\n        \"default\": 0.6,\n    },\n    \"condition_on_previous_text\": {\n        \"type\": bool,\n        \"description\": \"if True, the previous output of the model is provided as a prompt for the next window; disabling may make the text inconsistent across windows, but the model becomes less prone to getting stuck in a failure loop, such as repetition looping or timestamps going out of sync.\",\n        \"options\": None,\n        \"default\": True,\n    },\n    \"task\": {\n        \"type\": list,\n        \"description\": \"whether to perform X->X 'transcribe' or X->English 'translate'\",\n        \"options\": [\"transcribe\", \"translate\"],\n        \"default\": \"transcribe\",\n    },\n    \"language\": {\n        \"type\": str,\n        \"description\": \"language that the audio is in; uses detected language if None\",\n        \"options\": None,\n        \"default\": None,\n    },\n    \"best_of\": {\n        \"type\": int,\n        \"description\": \"number of independent samples to collect, when t > 0\",\n        \"options\": None,\n        \"default\": 5,\n    },\n    \"beam_size\": {\n        \"type\": int,\n        \"description\": \"number of beams in beam search, when t == 0\",\n        \"options\": None,\n        \"default\": 5,\n    },\n    \"patience\": {\n        \"type\": float,\n        \"description\": \"patience in beam search (https://arxiv.org/abs/2204.05424)\",\n        \"options\": None,\n        \"default\": 1.0,\n    },\n    \"length_penalty\": {\n        \"type\": float,\n        \"description\": \"'alpha' in Google NMT, None defaults to length norm\",\n        \"options\": None,\n        \"default\": 1.0,\n    },\n    \"prefix\": {\n        \"type\": str,\n        \"description\": \"text or tokens to prefix the current context\",\n        \"options\": None,\n        \"default\": None,\n    },\n    \"suppress_blank\": {\n        \"type\": bool,\n        \"description\": \"this will suppress blank outputs\",\n        \"options\": None,\n        \"default\": True,\n    },\n    \"suppress_tokens\": {\n        \"type\": Tuple,\n        \"description\": 'list of tokens ids (or comma-separated token ids) to suppress \"-1\" will suppress a set of symbols as defined in `tokenizer.non_speech_tokens()`',\n        \"options\": None,\n        \"default\": [-1],\n    },\n    \"without_timestamps\": {\n        \"type\": bool,\n        \"description\": \"use <|notimestamps|> to sample text tokens only\",\n        \"options\": None,\n        \"default\": False,\n    },\n    \"max_initial_timestamp\": {\n        \"type\": float,\n        \"description\": \"the initial timestamp cannot be later than this\",\n        \"options\": None,\n        \"default\": 1.0,\n    },\n    \"initial_prompt\": {\n        \"type\": str,\n        \"description\": \"Optional text to provide as a prompt for the first window.\",\n        \"options\": None,\n        \"default\": None,\n    },\n    \"word_timestamps\": {\n        \"type\": bool,\n        \"description\": \"Extract word-level timestamps using the cross-attention patternand dynamic time warping, and include the timestamps for each word in each segment.\",\n        \"options\": None,\n        \"default\": False,\n    },\n    \"prepend_punctuations\": {\n        \"type\": str,\n        \"description\": \"If word_timestamps is True, merge these punctuation symbolswith the next word\",\n        \"options\": None,\n        \"default\": \"\\\"'\u201c\u00bf([{-\",\n    },\n    \"append_punctuations\": {\n        \"type\": str,\n        \"description\": \"If word_timestamps is True, merge these punctuation symbolswith the previous word\",\n        \"options\": None,\n        \"default\": \"\\\"'.\u3002,\uff0c!\uff01?\uff1f:\uff1a\u201d)]}\u3001\",\n    },\n    \"vad_filter\": {\n        \"type\": bool,\n        \"description\": \"If True, use the integrated Silero VAD model to filter out parts of the audio without speech.\",\n        \"options\": None,\n        \"default\": False,\n    },\n    \"vad_parameters\": {\n        \"type\": dict,\n        \"description\": \"Parameters for splitting long audios into speech chunks using silero VAD.\",\n        \"options\": None,\n        \"default\": {\n            \"threshold\": 0.5,\n            \"min_speech_duration_ms\": 250,\n            \"max_speech_duration_s\": float(\"inf\"),\n            \"min_silence_duration_ms\": 2000,\n            \"window_size_samples\": 1024,\n            \"speech_pad_ms\": 400,\n        },\n    },\n}\n
"},{"location":"#subsai.models.faster_whisper_model.FasterWhisperModel.transcribe_configs","title":"transcribe_configs instance-attribute","text":"
transcribe_configs = {\n    config: _load_config(\n        config, model_config, self.config_schema\n    )\n    for config in self.config_schema\n    if not hasattr(self, f\"_{config}\")\n}\n
"},{"location":"#subsai.models.faster_whisper_model.FasterWhisperModel.model","title":"model instance-attribute","text":"
model = WhisperModel(\n    model_size_or_path=self._model_size_or_path,\n    device=self._device,\n    device_index=self._device_index,\n    compute_type=self._compute_type,\n    cpu_threads=self._cpu_threads,\n    num_workers=self._num_workers,\n)\n
"},{"location":"#subsai.models.faster_whisper_model.FasterWhisperModel.transcribe","title":"transcribe","text":"
transcribe(media_file)\n
Source code in src/subsai/models/faster_whisper_model.py
def transcribe(self, media_file) -> str:\n    segments, info = self.model.transcribe(media_file, **self.transcribe_configs)\n    subs = SSAFile()\n    if self.transcribe_configs['word_timestamps']:  # word level timestamps\n        for segment in segments:\n            for word in segment.words:\n                event = SSAEvent(start=pysubs2.make_time(s=word.start), end=pysubs2.make_time(s=word.end))\n                event.plaintext = word.word.strip()\n                subs.append(event)\n    else:\n        for segment in segments:\n            event = SSAEvent(start=pysubs2.make_time(s=segment.start), end=pysubs2.make_time(s=segment.end))\n            event.plaintext = segment.text.strip()\n            subs.append(event)\n    return subs\n
"},{"location":"#subsai.configs","title":"subsai.configs","text":"

Configurations file

"},{"location":"#subsai.configs.AVAILABLE_MODELS","title":"AVAILABLE_MODELS module-attribute","text":"
AVAILABLE_MODELS = {\n    \"openai/whisper\": {\n        \"class\": WhisperModel,\n        \"description\": \"Whisper is a general-purpose speech recognition model. It is trained on a large dataset of diverse audio and is also a multi-task model that can perform multilingual speech recognition as well as speech translation and language identification.\",\n        \"url\": \"https://github.com/openai/whisper\",\n        \"config_schema\": WhisperModel.config_schema,\n    },\n    \"linto-ai/whisper-timestamped\": {\n        \"class\": WhisperTimeStamped,\n        \"description\": \"Multilingual Automatic Speech Recognition with word-level timestamps and confidence.\",\n        \"url\": \"https://github.com/linto-ai/whisper-timestamped\",\n        \"config_schema\": WhisperTimeStamped.config_schema,\n    },\n    \"ggerganov/whisper.cpp\": {\n        \"class\": WhisperCppModel,\n        \"description\": \"High-performance inference of OpenAI's Whisper automatic speech recognition (ASR) model\\n* Plain C/C++ implementation without dependencies\\n* Runs on the CPU\\n\",\n        \"url\": \"https://github.com/ggerganov/whisper.cpp\\nhttps://github.com/abdeladim-s/pywhispercpp\",\n        \"config_schema\": WhisperCppModel.config_schema,\n    },\n    \"guillaumekln/faster-whisper\": {\n        \"class\": FasterWhisperModel,\n        \"description\": \"**faster-whisper** is a reimplementation of OpenAI's Whisper model using [CTranslate2](https://github.com/OpenNMT/CTranslate2/), which is a fast inference engine for Transformer models.\\nThis implementation is up to 4 times faster than [openai/whisper]( https://github.com/openai/whisper) for the same accuracy while using less memory. The efficiency can be further improved with 8-bit quantization on both CPU and GPU.\",\n        \"url\": \"https://github.com/guillaumekln/faster-whisper\",\n        \"config_schema\": FasterWhisperModel.config_schema,\n    },\n}\n
"},{"location":"#subsai.configs.BASIC_TOOLS_CONFIGS","title":"BASIC_TOOLS_CONFIGS module-attribute","text":"
BASIC_TOOLS_CONFIGS = {\n    \"set time\": {\n        \"description\": \"Set time to a subtitle\",\n        \"config_schema\": {\n            \"h\": {\n                \"type\": float,\n                \"description\": \"hours: Integer or float values, may be positive or negative\",\n                \"options\": None,\n                \"default\": 0,\n            },\n            \"m\": {\n                \"type\": float,\n                \"description\": \"minutes: Integer or float values, may be positive or negative\",\n                \"options\": None,\n                \"default\": 0,\n            },\n            \"s\": {\n                \"type\": float,\n                \"description\": \"seconds: Integer or float values, may be positive or negative\",\n                \"options\": None,\n                \"default\": 0,\n            },\n            \"ms\": {\n                \"type\": float,\n                \"description\": \"milliseconds: Integer or float values, may be positive or negative\",\n                \"options\": None,\n                \"default\": 0,\n            },\n        },\n    },\n    \"shift\": {\n        \"description\": \"Shift all subtitles by constant time amount\",\n        \"config_schema\": {\n            \"h\": {\n                \"type\": float,\n                \"description\": \"hours: Integer or float values, may be positive or negative\",\n                \"options\": None,\n                \"default\": 0,\n            },\n            \"m\": {\n                \"type\": float,\n                \"description\": \"minutes: Integer or float values, may be positive or negative\",\n                \"options\": None,\n                \"default\": 0,\n            },\n            \"s\": {\n                \"type\": float,\n                \"description\": \"seconds: Integer or float values, may be positive or negative\",\n                \"options\": None,\n                \"default\": 0,\n            },\n            \"ms\": {\n                \"type\": float,\n                \"description\": \"milliseconds: Integer or float values, may be positive or negative\",\n                \"options\": None,\n                \"default\": 0,\n            },\n            \"frames\": {\n                \"type\": int,\n                \"description\": \"When specified, must be an integer number of frames\",\n                \"options\": None,\n                \"default\": None,\n            },\n            \"fps\": {\n                \"type\": float,\n                \"description\": \"When specified, must be a positive number.\",\n                \"options\": None,\n                \"default\": None,\n            },\n        },\n    },\n}\n
"},{"location":"#subsai.configs.ADVANCED_TOOLS_CONFIGS","title":"ADVANCED_TOOLS_CONFIGS module-attribute","text":"
ADVANCED_TOOLS_CONFIGS = {\n    \"ffsubsync\": {\n        \"description\": \"Language-agnostic automatic synchronization of subtitles with video, so that subtitles are aligned to the correct starting point within the video.\",\n        \"url\": \"https://github.com/smacke/ffsubsync\",\n        \"config_schema\": {\n            \"vad\": {\n                \"type\": list,\n                \"description\": \"Which voice activity detector to use for speech extraction (if using video / audio as a reference\",\n                \"options\": [\n                    \"subs_then_webrtc\",\n                    \"webrtc\",\n                    \"subs_then_auditok\",\n                    \"auditok\",\n                    \"subs_then_silero\",\n                    \"silero\",\n                ],\n                \"default\": DEFAULT_VAD,\n            },\n            \"max-subtitle-seconds\": {\n                \"type\": float,\n                \"description\": \"Maximum duration for a subtitle to appear on-screen\",\n                \"options\": None,\n                \"default\": DEFAULT_MAX_SUBTITLE_SECONDS,\n            },\n            \"start-seconds\": {\n                \"type\": int,\n                \"description\": \"Start time for processing\",\n                \"options\": None,\n                \"default\": DEFAULT_START_SECONDS,\n            },\n            \"max-offset-seconds\": {\n                \"type\": float,\n                \"description\": \"The max allowed offset seconds for any subtitle segment\",\n                \"options\": None,\n                \"default\": DEFAULT_MAX_OFFSET_SECONDS,\n            },\n            \"apply-offset-seconds\": {\n                \"type\": float,\n                \"description\": \"Apply a predefined offset in seconds to all subtitle segments\",\n                \"options\": None,\n                \"default\": DEFAULT_APPLY_OFFSET_SECONDS,\n            },\n            \"suppress-output-if-offset-less-than\": {\n                \"type\": float,\n                \"description\": \"Apply a predefined offset in seconds to all subtitle segments\",\n                \"options\": None,\n                \"default\": None,\n            },\n            \"frame-rate\": {\n                \"type\": int,\n                \"description\": \"Frame rate for audio extraction\",\n                \"options\": None,\n                \"default\": DEFAULT_FRAME_RATE,\n            },\n            \"output-encoding\": {\n                \"type\": str,\n                \"description\": 'What encoding to use for writing output subtitles (default=utf-8). Can indicate \"same\" to use same encoding as that of the input.',\n                \"options\": None,\n                \"default\": \"utf-8\",\n            },\n            \"skip-infer-framerate-ratio\": {\n                \"type\": bool,\n                \"description\": \"If set, do not try to infer framerate ratio based on duration ratio.\",\n                \"options\": None,\n                \"default\": False,\n            },\n            \"no-fix-framerate\": {\n                \"type\": bool,\n                \"description\": \"If specified, subsync will not attempt to correct a framerate\",\n                \"options\": None,\n                \"default\": False,\n            },\n            \"serialize-speech\": {\n                \"type\": bool,\n                \"description\": \"If specified, serialize reference speech to a numpy array.\",\n                \"options\": None,\n                \"default\": False,\n            },\n            \"gss\": {\n                \"type\": bool,\n                \"description\": \"If specified, use golden-section search to try to findthe optimal framerate ratio between video and subtitles.\",\n                \"options\": None,\n                \"default\": False,\n            },\n        },\n    },\n    \"Translation\": {\n        \"description\": \"Translate to different languages using AI\",\n        \"url\": \"https://github.com/xhluca/dl-translate\",\n        \"config_schema\": {\n            \"model\": {\n                \"type\": list,\n                \"description\": \"The model\",\n                \"options\": available_translation_models(),\n                \"default\": available_translation_models()[\n                    0\n                ],\n            },\n            \"device\": {\n                \"type\": list,\n                \"description\": '\"cpu\", \"gpu\" or \"auto\". If it\\'s set to \"auto\", will try to select a GPU when available or else fall back to CPU',\n                \"options\": [\n                    \"auto\",\n                    get_available_devices(),\n                ],\n                \"default\": \"auto\",\n            },\n            \"batch_size\": {\n                \"type\": int,\n                \"description\": \"The number of samples to load at once. If set to `None`, it will process everything at once\\nA smaller value is preferred for `batch_size` if your (video) RAM is limited\",\n                \"options\": None,\n                \"default\": 32,\n            },\n            \"verbose\": {\n                \"type\": bool,\n                \"description\": \"Whether to display the progress bar for every batch processed.\",\n                \"options\": None,\n                \"default\": True,\n            },\n        },\n    },\n}\n
"}]} \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000..0f8724e --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..937083d1f35848bc368b9bef651575d5d7cee11a GIT binary patch literal 127 zcmV-_0D%7=iwFqlPjzGh|8r?{Wo=<_E_iKh04<9_3V)_WXo8&M?ytk3HC}0~zlG)Vu