PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.9.4
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.9.4
4.9.4 4.9.3 4.9.2 4.9.1 4.9.0 4.8.2 4.8.1 4.8.0 4.7.0 4.6.2 4.6.1 4.6.0 4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 4.5.1 4.5.0 4.4.1 4.4.0 3.3.4 3.4.0 3.4.1 3.4.2 All 202 releases
← All changes | includes/AI/Providers/OpenAIProvider.php +57 -0 4.8.1 → 4.9.4 View file →
@@ -46,8 +46,65 @@
46 46 return parent::build_payload( $model, $messages, $max_tokens, $temperature );
47 47 }
48 48
49 49 /**
50 + * Transcribe audio or video via OpenAI's speech-to-text endpoint.
51 + *
52 + * The endpoint accepts video containers (mp4, webm, mpeg) as well as audio
53 + * and reads the audio track out of them, which is why this feature needs no
54 + * ffmpeg on the host — something no WordPress host can be assumed to have.
55 + *
56 + * `response_format=text` returns the transcript as a bare string rather than
57 + * JSON; we ask for `json` instead so a provider error still decodes into the
58 + * usual `{ error: { message } }` shape that post_multipart() can report.
59 + *
60 + * @param array $file `[ 'path', 'filename', 'mime' ]`
61 + * @param array $options `[ 'model', 'timeout' ]`
62 + * @return string|\WP_Error
63 + */
64 + public function transcribe( $file, $options = array() ) {
65 + if ( empty( $this->api_key ) ) {
66 + return new \WP_Error( 'no_api_key', sprintf(
67 + /* translators: %s: provider label */
68 + __( '%s API key is not configured.', 'betterdocs' ),
69 + $this->label()
70 + ) );
71 + }
72 +
73 + $model = ! empty( $options['model'] ) ? (string) $options['model'] : 'gpt-4o-mini-transcribe';
74 + $timeout = isset( $options['timeout'] ) ? (int) $options['timeout'] : 120;
75 + $status = null;
76 +
77 + $data = $this->post_multipart(
78 + $this->base_url() . '/audio/transcriptions',
79 + array( 'Authorization' => 'Bearer ' . $this->api_key ),
80 + array(
81 + 'model' => $model,
82 + 'response_format' => 'json',
83 + ),
84 + array(
85 + 'name' => 'file',
86 + 'filename' => $file['filename'],
87 + 'type' => $file['mime'],
88 + 'path' => $file['path'],
89 + ),
90 + $timeout,
91 + $status
92 + );
93 +
94 + if ( is_wp_error( $data ) ) {
95 + return $data;
96 + }
97 +
98 + if ( isset( $data['error'] ) ) {
99 + $message = isset( $data['error']['message'] ) ? $data['error']['message'] : __( 'Unknown error.', 'betterdocs' );
100 + return new \WP_Error( 'provider_error', $this->classify_http_error( $status, $message, $model ) );
101 + }
102 +
103 + return isset( $data['text'] ) ? (string) $data['text'] : '';
104 + }
105 +
106 + /**
50 107 * Default reasoning_effort for a gpt-5* model.
51 108 *
52 109 * The original GPT-5 generation (gpt-5, gpt-5-mini, gpt-5-nano) accepts
53 110 * 'minimal'. The gpt-5.x point releases (e.g. gpt-5.5) dropped 'minimal'