@@ -74,7 +74,8 @@ def _safe_join(base: Path, rel: str) -> Path:
7474 """
7575 p = (base / rel ).resolve ()
7676 if base != p and base not in p .parents :
77- frappe .throw (_ ("Unsafe path: {0}" ).format (rel ))
77+ frappe .throw (_ ("Unsafe path: {0}\n "
78+ "Check Quick Start Guide Here 👇:\n {1}" ).format (rel ,CHANGAI_GUIDE_LINK ))
7879 return p
7980
8081
@@ -86,11 +87,13 @@ def read_asset(file_name: str, base: str = "assets") -> Any:
8687 """
8788 file_name = (file_name or "" ).strip ()
8889 if not file_name :
89- frappe .throw (_ ("file_name is required" ))
90+ frappe .throw (_ ("file_name is required\n "
91+ "Check Quick Start Guide Here 👇:\n {0}" ).format (CHANGAI_GUIDE_LINK ))
9092
9193 ext = Path (file_name ).suffix .lower ()
9294 if ext not in _ALLOWED_EXT :
93- frappe .throw (_ ("Unsupported file type: {0}" ).format (ext ))
95+ frappe .throw (_ ("Unsupported file type: {0}\n "
96+ "Check Quick Start Guide Here 👇:\n {1}" ).format (ext , CHANGAI_GUIDE_LINK ))
9497
9598 if base == "assets" :
9699 root = _ASSETS_DIR
@@ -99,25 +102,29 @@ def read_asset(file_name: str, base: str = "assets") -> Any:
99102 else :
100103 root = None
101104 if root is None :
102- frappe .throw (_ ("Invalid base: {0}" ).format (base ))
105+ frappe .throw (_ ("Invalid base: {0}\n "
106+ "Check Quick Start Guide Here 👇:\n {1}" ).format (base , CHANGAI_GUIDE_LINK ))
103107
104108 path = _safe_join (root , file_name )
105109
106110 if not path .is_file ():
107- frappe .throw (_ ("File not found: {0}" ).format (str (path )))
111+ frappe .throw (_ ("File not found: {0}\n "
112+ "Check Quick Start Guide Here 👇:\n {1}" ).format (str (path ), CHANGAI_GUIDE_LINK ))
108113
109114 content = path .read_text (encoding = "utf-8" , errors = "replace" )
110115
111116 if ext == ".json" :
112117 try :
113118 return json .loads (content )
114119 except json .JSONDecodeError as e :
115- frappe .throw (_ ("Invalid JSON in {0}: {1}" ).format (str (path ), str (e )))
120+ frappe .throw (_ ("Invalid JSON in {0}: {1}"
121+ "Check Quick Start Guide Here 👇:\n {2}" ).format (str (path ), str (e ), CHANGAI_GUIDE_LINK ))
116122 if ext == ".yaml" or ext == ".yml" :
117123 try :
118124 return yaml .safe_load (content )
119125 except yaml .YAMLError as e :
120- frappe .throw (_ ("Invalid YAML in {0}: {1}" ).format (str (path ), str (e )))
126+ frappe .throw (_ ("Invalid YAML in {0}: {1}"
127+ "Check Quick Start Guide Here 👇:\n {2}" ).format (str (path ), str (e ), CHANGAI_GUIDE_LINK ))
121128 return content
122129
123130_VS_TABLE = None
@@ -128,7 +135,11 @@ def read_asset(file_name: str, base: str = "assets") -> Any:
128135STATUS_200 = 200
129136_SUB_VS_CACHE = {}
130137APPLICATION_JSON = "application/json"
131- EMBEDDING_ENGINE_NONE_MESSG = "Embedding engine is None. Model not loaded."
138+ CHANGAI_GUIDE_LINK = "https://app.erpgulf.com/en/articles/chang-ai-quick-start-guide"
139+ EMBEDDING_ENGINE_NONE_MESSG = f"""
140+ Embedding engine is None. Model not loaded.
141+ Check Quick Start Guide Here 👇:
142+ { CHANGAI_GUIDE_LINK } """
132143MODEL_ID = "gemini-2.5-flash-lite"
133144RETRY_LIMIT = 2
134145BACKEND_SERVER_SETTINGS = "Backend Server Settings"
@@ -187,7 +198,7 @@ def download_model_from_ui():
187198
188199 except Exception as e :
189200 frappe .log_error (frappe .get_traceback (), "Embedding Model Download Failed" )
190- frappe .throw (f "Model download failed: { str (e )} " )
201+ frappe .throw (_ ( "Model download failed: {0} \n Check Quick Start Guide Here 👇: \n {1}" ). format ( str (e ), CHANGAI_GUIDE_LINK ) )
191202
192203
193204def get_embedding_engine ():
@@ -200,9 +211,9 @@ def get_embedding_engine():
200211 frappe .throw (
201212 _ (
202213 "Go to <b>ChangAI Settings</b> and click <b>'Download Embedding Model'</b>.<br><br>"
203- "Watch this documentation tutorial for more detail: "
204- "<a href='{0}' target='_blank'>Click here to watch </a>"
205- ).format ("https://your-docs-url-here.com" ),
214+ "Check this Quick Start Guide for more detail: "
215+ "<a href='{0}' target='_blank' rel='noopener noreferrer' style='color: #1e90ff;' >Click here</a>"
216+ ).format (CHANGAI_GUIDE_LINK ),
206217 title = _ ("Embedding Model Required" )
207218 )
208219
@@ -416,7 +427,8 @@ def whoami() -> Dict[str, Any]:
416427 mimetype = APPLICATION_JSON ,
417428 )
418429 except ValueError as ve :
419- frappe .throw (ve )
430+ frappe .throw (_ ("{0}\n Check Quick Start Guide Here 👇:\n {1}" ).format (ve ,CHANGAI_GUIDE_LINK ))
431+
420432
421433
422434def extract_tables_from_sql (sql : str ) -> List [str ]:
@@ -480,17 +492,20 @@ def _get_gemini_vertex_config(config):
480492def _throw_missing_vertex_field (project_id : str , location : str , credentials_json : str ) -> None :
481493 if not project_id :
482494 frappe .throw (
483- _ ("Gemini Project ID is missing.<br><br>Please go to <b>ChangAI Settings</b> and enter your <b>Gemini Project ID</b>." ),
495+ _ ("Gemini Project ID is missing.<br><br>Please go to <b>ChangAI Settings</b> and enter your <b>Gemini Project ID</b>.<br>"
496+ "Check Quick Start Guide 👇:<br><a href='{0}' target='_blank'>Click here</a>" ).format (CHANGAI_GUIDE_LINK ),
484497 title = _ ("Missing Gemini Project ID" ),
485498 )
486499 if not location :
487500 frappe .throw (
488- _ ("Gemini Location is missing.<br><br>Please go to <b>ChangAI Settings</b> and enter your <b>Gemini Location</b>." ),
501+ _ ("Gemini Location is missing.<br><br>Please go to <b>ChangAI Settings</b> and enter your <b>Gemini Location</b>.<br>"
502+ "Check Quick Start Guide 👇:<br><a href='{0}' target='_blank'>Click here</a>" ).format (CHANGAI_GUIDE_LINK ),
489503 title = _ ("Missing Gemini Location" ),
490504 )
491505 if not credentials_json :
492506 frappe .throw (
493- _ ("Service Account Credentials are missing.<br><br>Please go to <b>ChangAI Settings</b> and enter your <b>Service Account Credential</b>." ),
507+ _ ("Service Account Credentials are missing.<br><br>Please go to <b>ChangAI Settings</b> and enter your <b>Service Account Credential</b>.<br>"
508+ "Check Quick Start Guide 👇:<br><a href='{0}' target='_blank'>Click here</a>" ).format (CHANGAI_GUIDE_LINK ),
494509 title = _ ("Missing Service Account Credentials" ),
495510 )
496511
@@ -528,8 +543,9 @@ def _get_api_key_client(config):
528543 "<a href='https://aistudio.google.com/app/apikey' target='_blank'>Google AI Studio</a>.<br><br>"
529544 "<b>Option 2 (Vertex AI / Service Account):</b><br>"
530545 "Fill in <b>Gemini Project ID</b>, <b>Gemini Location</b>, "
531- "and <b>Service Account Credentials</b> in <b>ChangAI Settings</b>."
532- ),
546+ "and <b>Service Account Credentials</b> in <b>ChangAI Settings</b>.<br>"
547+ "ChangAI Quick Start Guide 👇:<br><a href='{0}' target='_blank' rel='noopener noreferrer' style='color: #1e90ff;'>Click here</a>"
548+ ).format (CHANGAI_GUIDE_LINK ),
533549 title = _ ("Gemini Authentication Not Configured" ),
534550 )
535551
@@ -564,28 +580,35 @@ def _clean_gemini_response_text(text: str) -> str:
564580def _handle_gemini_api_exception (e : Exception ) -> None :
565581 if isinstance (e , google_exceptions .ResourceExhausted ):
566582 frappe .throw (
567- _ ("Gemini API quota exceeded.<br><br>Please wait and try again or upgrade your plan." ),
583+ _ ("Gemini API quota exceeded.<br><br>Please wait and try again or upgrade your plan.<br>Check Quick Start Guide 👇:<br>"
584+ "<a href='{0}' target='_blank' rel='noopener noreferrer' style='color: #1e90ff;'>Click here</a>" ).format (CHANGAI_GUIDE_LINK ),
568585 title = _ ("Gemini Quota Exceeded" ),
569586 )
570587 if isinstance (e , google_exceptions .Unauthenticated ):
571588 frappe .throw (
572- _ ("Gemini API key is invalid.<br><br>Please go to <b>ChangAI Settings</b> and enter a valid <b>Gemini API Key</b>." ),
589+ _ ("Gemini API key is invalid.<br><br>Please go to <b>ChangAI Settings</b> and enter a valid <b>Gemini API Key</b>.<br>"
590+ "Check ChangAI Quick Start Guide 👇:<br><a href='{0}' target='_blank' rel='noopener noreferrer' style='color: #1e90ff;'>Click here</a>" ).format (CHANGAI_GUIDE_LINK ),
573591 title = _ ("Invalid Gemini API Key" ),
574592 )
575593 if isinstance (e , google_exceptions .PermissionDenied ):
576594 frappe .throw (
577- _ ("Gemini API permission denied.<br><br>Please check your API key permissions." ),
595+ _ ("Gemini API permission denied.<br><br>Please check your API key permissions.<br>"
596+ "Check ChangAI Quick Start Guide 👇:<br><a href='{0}' target='_blank' rel='noopener noreferrer' style='color: #1e90ff;'>Click here</a>" ).format (CHANGAI_GUIDE_LINK ),
578597 title = _ ("Gemini Permission Denied" ),
579598 )
580599 if isinstance (e , google_exceptions .InvalidArgument ):
581600 frappe .throw (
582- _ ("Invalid request to Gemini API: {0}" ).format (str (e )),
601+ _ ("Invalid request to Gemini API: {0}<br>"
602+ "Check ChangAI Quick Start Guide 👇:<br>"
603+ "<a href='{1}' target='_blank' rel='noopener noreferrer' style='color: #1e90ff;'>Click here</a>" ).format (str (e ),CHANGAI_GUIDE_LINK ),
583604 title = _ ("Gemini Invalid Request" ),
584605 )
585606
586607 frappe .log_error (frappe .get_traceback (), "Gemini API Unexpected Error" )
587608 frappe .throw (
588- _ ("Gemini API error: {0}" ).format (str (e )),
609+ _ ("Gemini API error: {0}<br>"
610+ "Check ChangAI Quick Start Guide 👇:<br>"
611+ "<a href='{1}' target='_blank' rel='noopener noreferrer' style='color: #1e90ff;'>Click here</a>" ).format (str (e ),CHANGAI_GUIDE_LINK ),
589612 title = _ ("Gemini API Error" ),
590613 )
591614
@@ -789,13 +812,6 @@ def _parse_rewrite_response(raw: Any, user_qstn: str) -> Tuple[str, bool]:
789812@traceable (name = "rewrite_question" , run_type = "tool" )
790813def rewrite_question (state : SQLState ) -> SQLState :
791814 request_id = state .get ("request_id" )
792-
793- # publish_pipeline_update(
794- # request_id,
795- # "question_rewrite_start",
796- # "Rewriting user question"
797- # )
798-
799815 user_qstn = state .get ("question" ) or ""
800816 session_id = state .get ("session_id" )
801817
@@ -852,7 +868,8 @@ def get_table_vs():
852868 )
853869
854870 if not os .path .exists (table_vs_path ):
855- frappe .throw (_ ("FAISS table store not found at {0}" ).format (table_vs_path ))
871+ frappe .throw (_ ("FAISS table store not found at {0}\n "
872+ "Check Quick Start Guide Here 👇:\n {1}" ).format (table_vs_path ,CHANGAI_GUIDE_LINK ))
856873
857874 _VS_TABLE = FAISS .load_local (
858875 table_vs_path ,
@@ -876,7 +893,8 @@ def get_table_vs_test():
876893 )
877894
878895 if not os .path .exists (table_vs_path ):
879- frappe .throw (_ ("FAISS table store not found at {0}" ).format (table_vs_path ))
896+ frappe .throw (_ ("FAISS table store not found at {0} <br>"
897+ f"Check Quick Start Guide Here 👇:\n { 1 } " ).format (table_vs_path ,CHANGAI_GUIDE_LINK ))
880898
881899 _VS_TABLE = FAISS .load_local (
882900 table_vs_path ,
@@ -988,7 +1006,8 @@ def get_full_fields_vs_test():
9881006 )
9891007
9901008 if not os .path .isdir (full_fields_vs_path ):
991- frappe .throw (_ ("Vector store path not found: {0}" ).format (full_fields_vs_path ))
1009+ frappe .throw (_ ("Vector store path not found: {0}"
1010+ "Check Quick Start Guide Here 👇:\n {1}" ).format (full_fields_vs_path , CHANGAI_GUIDE_LINK ))
9921011
9931012 _FULL_FIELDS_VS = FAISS .load_local (
9941013 full_fields_vs_path ,
@@ -1014,7 +1033,8 @@ def get_full_fields_vs():
10141033 )
10151034
10161035 if not os .path .isdir (full_fields_vs_path ):
1017- frappe .throw (_ ("Vector store path not found: {0}" ).format (full_fields_vs_path ))
1036+ frappe .throw (_ ("Vector store path not found: {0} <br>"
1037+ "Check Quick Start Guide Here 👇:\n {1}" ).format (full_fields_vs_path ,CHANGAI_GUIDE_LINK ))
10181038
10191039 _FULL_FIELDS_VS = FAISS .load_local (
10201040 full_fields_vs_path ,
@@ -1235,7 +1255,8 @@ def get_master_vs():
12351255 )
12361256
12371257 if not os .path .exists (master_vs_path ):
1238- frappe .throw (_ ("FAISS MASTER store not found at {0}.Please click on Update Master Data button in Training tab in ChangAI Settings" ).format (master_vs_path ))
1258+ frappe .throw (_ (f"FAISS MASTER store not found at { 0 } .Please click on Update Master Data button in Training tab in ChangAI Settings"
1259+ f"Check Quick Start Guide Here 👇:\n { 1 } " ).format (master_vs_path , CHANGAI_GUIDE_LINK ))
12391260
12401261 _VS_MASTER = FAISS .load_local (
12411262 master_vs_path ,
@@ -1576,13 +1597,14 @@ def execute_query(sql: str, doctypes: List[str]) -> Any:
15761597 if not sql :
15771598 return []
15781599 if not str (sql ).lower ().strip ().startswith ("select" ):
1579- frappe .throw (_ ("Only SELECT queries are allowed." ))
1600+ frappe .throw (_ ("Only SELECT queries are allowed."
1601+ "Check Quick Start Guide Here 👇:\n {0}" ).format (CHANGAI_GUIDE_LINK ))
15801602 combined = _build_match_conditions (doctypes )
15811603 if combined :
15821604 sql = _append_conditions (sql , combined )
15831605 return frappe .db .sql (sql , as_dict = True )
15841606 except Exception as e :
1585- return {"error" : f"SQL Execution Failed: { e } " }
1607+ return {"error" : f"SQL Execution Failed: { e } \n Check Quick Start Guide Here 👇: \n { CHANGAI_GUIDE_LINK } " }
15861608
15871609
15881610@frappe .whitelist (allow_guest = False )
@@ -2037,8 +2059,8 @@ def _invoke_pipeline(user_question: str, chat_id: str, request_id: str):
20372059 try :
20382060 return app .invoke (initial_state , config = config ), None
20392061 except frappe .exceptions .ValidationError as e :
2040- clean_msg = re .sub (r'<[^>]+>' , '' , str (e ))
2041- return None , {"Bot" : clean_msg , "error" : clean_msg }
2062+ # clean_msg = re.sub(r'<[^>]+>', '', str(e))
2063+ return None , {"Bot" : str ( e ) , "error" : str ( e ) }
20422064 except Exception as e :
20432065 frappe .log_error (frappe .get_traceback (), "ChangAI Pipeline Invoke Error" )
20442066 return None , {"Bot" : "⚠️ An unexpected error occurred. Please try again." , "error" : str (e )}
0 commit comments