@@ -54,13 +54,28 @@ export default eventHandler(async (event) => {
5454
5555 const response = await AI . run ( aiModel as keyof AiModels , {
5656 messages,
57- chat_template_kwargs : {
58- enable_thinking : false ,
59- } ,
6057 } ) as AiChatResponse
6158
6259 let content = response . response ?? response . choices ?. [ 0 ] ?. message ?. content ?? ''
6360
61+ if ( ! content || content . trim ( ) === '' ) {
62+ console . error ( 'AI OG response is empty. Fallback initiated.' )
63+ try {
64+ const urlObj = new URL ( url )
65+ const domain = urlObj . hostname . replace ( 'www.' , '' )
66+ return {
67+ title : domain ,
68+ description : `Short link for ${ url } ` ,
69+ }
70+ }
71+ catch {
72+ return {
73+ title : 'Short Link' ,
74+ description : 'Check out this link on Sink.' ,
75+ }
76+ }
77+ }
78+
6479 // 1. Try to strip markdown code block wrapper (e.g. ```json\n{...}\n```)
6580 const codeBlockMatch = content . match ( / ` ` ` (?: j s o n ) ? \n ( [ \s \S ] * ?) ` ` ` / )
6681 if ( codeBlockMatch ?. [ 1 ] ) {
@@ -91,22 +106,61 @@ export default eventHandler(async (event) => {
91106 // Ensure we always return an object with title and description properties
92107 if ( typeof parsed !== 'object' || parsed === null || Array . isArray ( parsed ) ) {
93108 // Attempt to extract title and description as best effort from the raw content
94- // E.g. "Title: My Title\nDescription: My description"
95- const titleMatch = content . match ( / t i t l e : \s * ( [ ^ \n ] + ) / i) || content . match ( / " t i t l e " \s * : \s * " ( (?: [ ^ " \\ ] | \\ .) + ) " / )
96- const descMatch = content . match ( / d e s c r i p t i o n : \s * ( [ ^ \n ] + ) / i) || content . match ( / " d e s c r i p t i o n " \s * : \s * " ( (?: [ ^ " \\ ] | \\ .) + ) " / )
109+ // Check multiple common formats: JSON-like, YAML-like, or plain text labels
110+ const titlePatterns = [
111+ / " t i t l e " \s * : \s * " ( [ ^ " ] + ) " / ,
112+ / t i t l e : \s * ( [ ^ \n ] + ) / i,
113+ / ^ t i t l e \s * = \s * ( .* ) / im,
114+ / < t i t l e > ( [ ^ < ] + ) < \/ t i t l e > / i,
115+ ]
116+
117+ const descPatterns = [
118+ / " d e s c r i p t i o n " \s * : \s * " ( [ ^ " ] + ) " / ,
119+ / d e s c r i p t i o n : \s * ( [ ^ \n ] + ) / i,
120+ / ^ d e s c r i p t i o n \s * = \s * ( .* ) / im,
121+ ]
122+
123+ let extractedTitle = ''
124+ let extractedDesc = ''
125+
126+ for ( const pattern of titlePatterns ) {
127+ const match = content . match ( pattern )
128+ if ( match ?. [ 1 ] ) {
129+ extractedTitle = match [ 1 ] . replace ( / ^ [ " ' ] | [ " ' ] $ / g, '' ) . trim ( )
130+ break
131+ }
132+ }
97133
98- if ( titleMatch && titleMatch [ 1 ] && descMatch && descMatch [ 1 ] ) {
134+ for ( const pattern of descPatterns ) {
135+ const match = content . match ( pattern )
136+ if ( match ?. [ 1 ] ) {
137+ extractedDesc = match [ 1 ] . replace ( / ^ [ " ' ] | [ " ' ] $ / g, '' ) . trim ( )
138+ break
139+ }
140+ }
141+
142+ if ( extractedTitle || extractedDesc ) {
99143 parsed = {
100- title : titleMatch [ 1 ] . replace ( / ^ [ " ' ] | [ " ' ] $ / g , '' ) . trim ( ) ,
101- description : descMatch [ 1 ] . replace ( / ^ [ " ' ] | [ " ' ] $ / g , '' ) . trim ( ) ,
144+ title : extractedTitle || 'Link' ,
145+ description : extractedDesc || 'No description provided.' ,
102146 }
103147 }
104148 else {
105- console . error ( 'AI OG response parsing failed. Raw content:' , content )
106- throw createError ( {
107- statusCode : 500 ,
108- statusMessage : 'Invalid AI response format' ,
109- } )
149+ console . error ( 'AI OG response parsing failed. Final content:' , content )
150+ // Final fallback instead of throwing
151+ try {
152+ const urlObj = new URL ( url )
153+ parsed = {
154+ title : urlObj . hostname ,
155+ description : `Short link for ${ url } ` ,
156+ }
157+ }
158+ catch {
159+ parsed = {
160+ title : 'Short Link' ,
161+ description : 'No metadata available.' ,
162+ }
163+ }
110164 }
111165 }
112166
0 commit comments