Summary
I’m trying to create a healthcare chatbot (Aira) that calls the OpenAI API from a Server Script, but I’m getting ImportError: __import__ not found even after using Frappe-safe methods.
Environment
- Site: airtook.com
- Bench Type: Private Bench (recently migrated from shared)
- Frappe Version: [v16 Nightly]
- App: Healthcare (Marley Health module)
- Use Case: AI health assistant for telemedicine platform in Nigeria
What I’m Trying to Do
Create a Server Script that:
- Accepts patient health questions via
frappe.call() - Calls OpenAI ChatGPT API (
gpt-4o-mini) - Returns AI response to the frontend
- Logs conversations for medical records
Server Script Configuration
Script Type: API
API Method: airtook.chat_with_aira
Allow Guest: No (unchecked)
Enabled: Yes (checked)
The Code
@frappe.whitelist()
def chat_with_aira(message, conversation_history=None):
try:
# Security check
if frappe.session.user == 'Guest':
return {'success': False, 'error': 'Please login'}
# Get API key from custom DocType
settings = frappe.get_doc('AirTook API Settings', 'AirTook API Settings')
api_key = settings.get_password('openai_api_key')
if not api_key:
return {'success': False, 'error': 'API not configured'}
# Build messages
messages = [
{"role": "system", "content": "You are a health assistant."},
{"role": "user", "content": message}
]
# Call OpenAI using frappe's integration util
from frappe.integrations.utils import make_post_request
url = "https://api.openai.com/v1/chat/completions"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {api_key}"
}
# Using frappe.as_json (not json.dumps)
payload_str = frappe.as_json({
"model": "gpt-4o-mini",
"messages": messages,
"max_tokens": 300
})
# Make request
response_data = make_post_request(url, headers=headers, data=payload_str)
if not response_data:
return {'success': False, 'error': 'No response from API'}
ai_response = response_data.get('choices', [{}])[0].get('message', {}).get('content', '')
return {
'success': True,
'response': ai_response
}
except Exception as e:
frappe.log_error(title="Aira Error", message=str(e))
return {'success': False, 'error': str(e)}
```
## Frontend Call (Web Page)
```javascript
frappe.call({
method: 'airtook.chat_with_aira',
args: { message: 'I have a headache' },
callback: r => console.log('Response:', r.message),
error: e => console.error('Error:', e)
});
```
## Error I'm Getting
**Browser Console:**
```
POST https://airtook.com/ 500 (Internal Server Error)
Traceback (most recent call last):
File "apps/frappe/frappe/handler.py", line 90, in run_server_script
response = frappe.get_doc("Server Script", server_script).execute_method()
File "apps/frappe/frappe/core/doctype/server_script/server_script.py", line 275, in execute_api_server_script
_globals, _locals = safe_exec(script.script, script_filename=script.name)
File "apps/frappe/frappe/utils/safe_exec.py", line 120, in safe_exec
exec(_compile_code(script, filename=filename), exec_globals, _locals)
File "<serverscript>: aira_chatgpt_integration", line 12, in <module>
ImportError: __import__ not found
```
## What I’ve Already Tried
**No `import json`** - Using `frappe.parse_json()` and `frappe.as_json()` instead
**No `import requests`** - Using `frappe.integrations.utils.make_post_request`
**Verified script is Enabled**
**API Method name matches** in `frappe.call()`
**Created custom DocType** for storing API keys securely
**Tested on simple Server Script** - Same error
## Questions
1. **Is `make_post_request` the correct way** to call external APIs from Server Scripts?
2. **Are there additional imports or libraries** I need to add to my bench?
3. **What are ALL the allowed imports** in the `safe_exec` sandbox?
4. **Is there a better pattern** for calling external REST APIs from Frappe?
5. **Should I use a different approach entirely?** (Custom API endpoint in app, Client Script, etc.) ## Context: Why Server Script?