|
1 |
| -from llmstack.sheets.apis import PromptlySheetViewSet |
| 1 | +import logging |
| 2 | +import uuid |
2 | 3 |
|
| 4 | +from asgiref.sync import async_to_sync |
| 5 | +from channels.layers import get_channel_layer |
| 6 | +from django.contrib.auth.models import User |
| 7 | +from django.test import RequestFactory |
| 8 | +from rest_framework.response import Response as DRFResponse |
3 | 9 |
|
4 |
| -def process_sheet_execute_request(user_email, sheet_id): |
5 |
| - from django.contrib.auth.models import User |
6 |
| - from django.test import RequestFactory |
| 10 | +from llmstack.common.utils.utils import hydrate_input |
| 11 | +from llmstack.sheets.models import PromptlySheet, PromptlySheetCell, PromptlySheetColumn |
| 12 | +from llmstack.sheets.serializers import PromptlySheetSerializer |
7 | 13 |
|
8 |
| - user = User.objects.get(email=user_email) |
| 14 | +try: |
| 15 | + from promptly.promptly_app_store.apis import AppStoreAppViewSet |
| 16 | +except ImportError: |
| 17 | + from llmstack.app_store.apis import AppStoreAppViewSet |
| 18 | + |
| 19 | + |
| 20 | +logger = logging.getLogger(__name__) |
| 21 | +channel_layer = get_channel_layer() |
| 22 | + |
| 23 | + |
| 24 | +def number_to_letters(num): |
| 25 | + letters = "" |
| 26 | + while num >= 0: |
| 27 | + letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[num % 26] + letters |
| 28 | + num = num // 26 - 1 |
| 29 | + return letters |
| 30 | + |
| 31 | + |
| 32 | +def _execute_cell( |
| 33 | + cell: PromptlySheetCell, |
| 34 | + column: PromptlySheetColumn, |
| 35 | + row: dict[str, PromptlySheetCell], |
| 36 | + sheet: PromptlySheet, |
| 37 | + run_id: str, |
| 38 | + user: User, |
| 39 | +) -> PromptlySheetCell: |
| 40 | + if column.kind != "app_run": |
| 41 | + return cell |
| 42 | + |
| 43 | + async_to_sync(channel_layer.group_send)(run_id, {"type": "cell.updating", "cell": {"id": cell.cell_id}}) |
| 44 | + |
| 45 | + app_slug = column.data["app_slug"] |
| 46 | + input_values = {number_to_letters(col): cell.data for col, cell in row.items()} |
| 47 | + input = hydrate_input(column.data["input"], input_values) |
9 | 48 |
|
10 | 49 | request = RequestFactory().post(
|
11 |
| - f"/api/sheets/{sheet_id}/execute", |
| 50 | + f"/api/store/apps/{app_slug}", |
12 | 51 | format="json",
|
13 | 52 | )
|
| 53 | + request.data = { |
| 54 | + "stream": False, |
| 55 | + "input": input, |
| 56 | + } |
14 | 57 | request.user = user
|
15 |
| - response = PromptlySheetViewSet().execute(request, sheet_uuid=sheet_id) |
16 | 58 |
|
17 |
| - return {"status_code": response.status_code, "data": response} |
| 59 | + # Execute the app |
| 60 | + response = async_to_sync(AppStoreAppViewSet().run_app_internal_async)( |
| 61 | + slug=app_slug, |
| 62 | + session_id=None, |
| 63 | + request_uuid=str(uuid.uuid4()), |
| 64 | + request=request, |
| 65 | + ) |
| 66 | + |
| 67 | + output = response.get("output", "") |
| 68 | + async_to_sync(channel_layer.group_send)( |
| 69 | + run_id, {"type": "cell.update", "cell": {"id": cell.cell_id, "data": response.get("output", "")}} |
| 70 | + ) |
| 71 | + cell.data = output |
| 72 | + |
| 73 | + return cell |
| 74 | + |
| 75 | + |
| 76 | +def run_sheet(sheet, run_entry, user): |
| 77 | + try: |
| 78 | + processed_cells = [] |
| 79 | + existing_rows = list(sheet.rows) |
| 80 | + existing_cols = sheet.columns |
| 81 | + |
| 82 | + for row_number in range(sheet.data.get("total_rows", 0)): |
| 83 | + # Find existing row and the cell |
| 84 | + existing_row = next(filter(lambda row: row[0] == row_number, existing_rows), None) |
| 85 | + existing_row_cells = existing_row[1] if existing_row else {} |
| 86 | + |
| 87 | + for column in existing_cols: |
| 88 | + if column.kind != "app_run": |
| 89 | + if existing_row: |
| 90 | + existing_cell = next( |
| 91 | + filter(lambda cell: cell.col == column.col, existing_row_cells.values()), None |
| 92 | + ) |
| 93 | + if existing_cell: |
| 94 | + processed_cells.append(existing_cell) |
| 95 | + continue |
| 96 | + |
| 97 | + # Create a new cell |
| 98 | + cell_to_execute = PromptlySheetCell( |
| 99 | + row=row_number, |
| 100 | + col=column.col, |
| 101 | + kind=column.kind, |
| 102 | + ) |
| 103 | + processed_cells.append( |
| 104 | + _execute_cell(cell_to_execute, column, existing_row_cells, sheet, str(run_entry.uuid), user) |
| 105 | + ) |
| 106 | + |
| 107 | + if processed_cells: |
| 108 | + sheet.save(cells=processed_cells, update_fields=["updated_at"]) |
| 109 | + # Store the processed data in sheet runs table |
| 110 | + run_entry.save(cells=processed_cells) |
| 111 | + |
| 112 | + except Exception: |
| 113 | + logger.exception("Error executing sheet") |
| 114 | + |
| 115 | + sheet.is_locked = False |
| 116 | + sheet.save(update_fields=["is_locked"]) |
| 117 | + return DRFResponse(PromptlySheetSerializer(instance=sheet).data) |
0 commit comments