darsoarafa commited on
Commit
be1ef50
·
verified ·
1 Parent(s): 5056bb9

Delete start.py

Browse files
Files changed (1) hide show
  1. start.py +0 -521
start.py DELETED
@@ -1,521 +0,0 @@
1
- from __future__ import annotations as _annotations
2
- import os
3
- import asyncio
4
- import json
5
- import sqlite3
6
- import datetime
7
- import fastapi
8
- import logfire
9
- import time
10
- from collections.abc import AsyncIterator
11
- from concurrent.futures.thread import ThreadPoolExecutor
12
- from contextlib import asynccontextmanager
13
- from dataclasses import dataclass
14
- from datetime import datetime, timezone, date
15
- from functools import partial
16
- from pathlib import Path
17
- from typing import Annotated, Any, Callable, Literal, TypeVar
18
-
19
- from pydantic import BaseModel, Field, ValidationError, model_validator
20
- from typing import List, Optional, Dict
21
-
22
- from fastapi import Depends, Request
23
- from fastapi.responses import FileResponse, Response, StreamingResponse
24
- from typing_extensions import LiteralString, ParamSpec, TypedDict
25
-
26
- from pydantic_ai import Agent
27
- from pydantic_ai.exceptions import UnexpectedModelBehavior
28
- from pydantic_ai.messages import (
29
- ModelMessage,
30
- ModelMessagesTypeAdapter,
31
- ModelRequest,
32
- ModelResponse,
33
- TextPart,
34
- UserPromptPart,
35
- )
36
- from pydantic_ai.models.openai import OpenAIModel
37
-
38
- model = OpenAIModel(
39
- 'gemma-2-2b-it',
40
- base_url='http://localhost:1234/v1',
41
- api_key='your-local-api-key',
42
- )
43
- model11 = OpenAIModel(
44
- 'mistral-7b-instruct-v0.3',
45
- base_url='http://localhost:1234/v1',
46
- api_key='your-local-api-key',
47
- )
48
-
49
- #DeepSeek Key: sk-694660c67c3947e4853019473f30240d https://api.deepseek.com
50
- # Model Pydantic untuk Sales Order
51
- class Item(BaseModel):
52
- product_code: Optional[str] = None #str = Field(..., min_length=1, max_length=20)
53
- description: str = Field(..., min_length=1, max_length=100)
54
- quantity: int = Field(..., ge=1)
55
- unit_price: float = Field(..., ge=0)
56
-
57
- class SalesOrder1(BaseModel):
58
- so_number: Optional[str] = None
59
- customer_name: str = Field(..., min_length=1, max_length=100)
60
- items: List[Item] = Field(..., min_items=1)
61
- payment_terms: Optional[str] = None
62
- shipping_address: Optional[str] = None
63
- #order_date: datetime = None
64
-
65
- # 'if-token-present' means nothing will be sent (and the example will work) if you don't have logfire configured
66
- logfire.configure(send_to_logfire='if-token-present')
67
-
68
- class product(BaseModel):
69
- ds_productCode: Optional[str] = "" #str = Field(..., min_length=1, max_length=20)
70
- ds_productName: str = Field(..., min_length=1, max_length=100)
71
- ds_quantity: int = Field(..., ge=1)
72
- ds_unitPrice: float = Field(..., ge=0)
73
- ds_itemAmt: Optional[float] = 0
74
-
75
- class SalesOrder(BaseModel):
76
- ds_salesOrderId: Optional[str] = ""
77
- ds_salesDate: Optional[str] = ""
78
- ds_customerName: str = Field(..., min_length=1, max_length=100)
79
- ds_customerAddress: Optional[str] = ""
80
- ds_items: List[product] = Field(..., min_items=1)
81
- ds_shippingCost:Optional[float] = ""
82
- ds_shippingAddress: Optional[str] = ""
83
- ds_totalAmount:Optional[float] = ""
84
- #ds_paymentTerms: Optional[str] = ""
85
- os.environ['GEMINI_API_KEY'] = 'AIzaSyAsVIHsPIIfDBTb2K6VNdNlMt05t8x3mtE'
86
- #agent= Agent('gemini-1.5-flash', result_type=SalesOrder)
87
-
88
- # # Create a system prompt to guide the model
89
- SYSTEM_PROMPT = """
90
- You are a helper that extracts SalesOrder information from text and formats it as a SalesOrder class.
91
- """
92
- #agent3 = Agent(model=ollama_model, result_type=PetList, retries=3, system_prompt=SYSTEM_PROMPT)
93
- #agent3 = Agent(model=ollama_model, retries=3, system_prompt=SYSTEM_PROMPT)
94
-
95
-
96
-
97
- agent = Agent('gemini-1.5-flash') # OK-1
98
- #agent = Agent(model) # OK-2
99
-
100
-
101
-
102
- #agent = Agent(model, result_type=SalesOrder) # belum bisa untuk local
103
- #agent = Agent(model, system_prompt=SYSTEM_PROMPT) # belum bisa untuk local
104
- #agent= Agent('gemini-1.5-flash', system_prompt=SYSTEM_PROMPT) # ERR
105
- THIS_DIR = Path(__file__).parent
106
-
107
-
108
- @asynccontextmanager
109
- async def lifespan(_app: fastapi.FastAPI):
110
- async with Database.connect() as db:
111
- yield {'db': db}
112
-
113
-
114
- app = fastapi.FastAPI(lifespan=lifespan)
115
- logfire.instrument_fastapi(app)
116
-
117
-
118
- @app.get('/')
119
- async def index() -> FileResponse:
120
- return FileResponse((THIS_DIR / 'chat_app.html'), media_type='text/html')
121
-
122
-
123
- @app.get('/chat_app.ts')
124
- async def main_ts() -> FileResponse:
125
- """Get the raw typescript code, it's compiled in the browser, forgive me."""
126
- return FileResponse((THIS_DIR / 'chat_app.ts'), media_type='text/plain')
127
-
128
-
129
- async def get_db(request: Request) -> Database:
130
- return request.state.db
131
-
132
- @app.get('/chat/')
133
- async def get_chat(database: Database = Depends(get_db)) -> Response:
134
- msgs = await database.get_messages()
135
- return Response(
136
- b'\n'.join(json.dumps(to_chat_message(m)).encode('utf-8') for m in msgs),
137
- media_type='text/plain',
138
- )
139
-
140
-
141
-
142
- class ChatMessage(TypedDict):
143
- """Format of messages sent to the browser."""
144
-
145
- role: Literal['user', 'model']
146
- timestamp: str
147
- content: str
148
-
149
-
150
- def to_chat_message(m: ModelMessage) -> ChatMessage:
151
- first_part = m.parts[0]
152
- if isinstance(m, ModelRequest):
153
- if isinstance(first_part, UserPromptPart):
154
- return {
155
- 'role': 'user',
156
- 'timestamp': first_part.timestamp.isoformat(),
157
- 'content': first_part.content,
158
- }
159
- elif isinstance(m, ModelResponse):
160
- if isinstance(first_part, TextPart):
161
- return {
162
- 'role': 'model',
163
- 'timestamp': m.timestamp.isoformat(),
164
- 'content': first_part.content,
165
- }
166
- raise UnexpectedModelBehavior(f'Unexpected message type for chat app: {m}')
167
-
168
- def to_ds_message(m: ModelMessage) -> SalesOrder:
169
- first_part = m.parts[0]
170
- if isinstance(m, ModelRequest):
171
- if isinstance(first_part, UserPromptPart):
172
- return {
173
- 'role': 'user',
174
- 'timestamp': first_part.timestamp.isoformat(),
175
- 'content': first_part.content,
176
- }
177
- elif isinstance(m, ModelResponse):
178
- if isinstance(first_part, TextPart):
179
- return {
180
- 'role': 'model',
181
- 'timestamp': m.timestamp.isoformat(),
182
- 'content': first_part.content,
183
- }
184
- raise UnexpectedModelBehavior(f'Unexpected message type for chat app: {m}')
185
-
186
- @app.post('/chat/')
187
- async def post_chat(
188
- prompt: Annotated[str, fastapi.Form()], database: Database = Depends(get_db)
189
- ) -> StreamingResponse:
190
- async def stream_messages():
191
- """Streams new line delimited JSON `Message`s to the client."""
192
- # stream the user prompt so that can be displayed straight away
193
- yield (
194
- json.dumps(
195
- {
196
- 'role': 'user',
197
- 'timestamp': datetime.now(tz=timezone.utc).isoformat(),
198
- 'content': prompt,
199
- }
200
- ).encode('utf-8')
201
- + b'\n'
202
- )
203
- # get the chat history so far to pass as context to the agent
204
- messages = await database.get_messages()
205
- # run the agent with the user prompt and the chat history
206
- async with agent.run_stream(prompt, message_history=messages) as result:
207
- async for text in result.stream(debounce_by=0.01):
208
- # text here is a `str` and the frontend wants
209
- # JSON encoded ModelResponse, so we create one
210
- m = ModelResponse.from_text(content=text, timestamp=result.timestamp())
211
- yield json.dumps(to_chat_message(m)).encode('utf-8') + b'\n'
212
-
213
- # add new messages (e.g. the user prompt and the agent response in this case) to the database
214
- #print("---",result.new_messages_json(),"---")
215
- #print("***",prompt,"***")
216
- await database.add_messages(result.new_messages_json())
217
- async def ds_messages(prompt1):
218
- #Nama pembeli: Bu Lurah, alamat Bekasi Barat, hari ini membeli Teh Putih dua kaleng harga 110000 per kaleng, juga membeli Teh Hitam 3 kaleng, harga per kaleng 60000. Ongkos kirim ke Bekasi Barat sebesar 36 ribu
219
- #nama pembeli Mas Anang alamat di Jalan Cisitu no.5 Bandung, membeli Chocobar 5 batang harga 15 ribu per batang, dan membeli Rice Cracker 4 buah harga 20 ribu per buah, ongkos kirim ke Jalan Cisitu no.5 sebesar 7 ribu rupiah
220
- try:
221
- prompt2=f"Ekstrak data Sales Order dari teks: {prompt1}. Format output yang diinginkan hanya berupa JSON saja sesuai class SalesOrder. Tidak usah ada penjelasan lain. Sekali lagi: Output hanya JSON saja. Hari ini adalah tanggal {date.today()}. untuk Nomor Sales Order pasangkan dengan key ds_salesOrderId, untuk Tanggal Sales pasangkan dengan key ds_salesDate, untuk Nama Customer pasangkan dengan Key ds_customerName, untuk Alamat Customer pasangkan dengan key ds_customerAddress, untuk Daftar Item Barang pasangkan dengan key ds_items, untuk Kode Barang pasangkan dengan key ds_productCode, untuk Nama Barang pasangkan dengan key ds_productName, untuk Quantity pasangkan dengan key ds_quantity, untuk Unit Price pasangkan dengan key ds_unitPrice, untuk Total Nilai Per Baris Barang pasangkan dengan key ds_itemAmt, untuk Ongkos Kirim pasangkan dengan key ds_shippingCost, untuk Alamat Pengiriman pasangkan dengan key ds_shippingAddress, untuk Total Nilai Sales Order pasangkan dengan key ds_totalAmount"
222
- #prompt2=f"Ekstrak data Sales Order dari teks: {prompt1}. Hari ini adalah tanggal {date.today()}"
223
- yield (
224
- json.dumps(
225
- {
226
- 'role': 'user',
227
- 'timestamp': datetime.now(tz=timezone.utc).isoformat(),
228
- 'content': prompt1,
229
- }
230
- ).encode('utf-8')
231
- + b'\n'
232
- )
233
- messages = await database.get_messages()
234
- async with agent.run_stream(prompt2, message_history=messages) as result:
235
- async for text in result.stream(debounce_by=0.1):
236
- m = ModelResponse.from_text(content=text, timestamp=result.timestamp())
237
- yield json.dumps(to_ds_message(m)).encode('utf-8') + b'\n'
238
-
239
- ##print(result.usage())
240
- #await database.add_messages(result.new_messages_json())
241
- darso = json.loads(result.new_messages_json())
242
- darso1= darso[1]
243
- #print("1|", darso1)
244
- darso2= json.loads(json.dumps(darso1))
245
- #print("2|",darso2['parts'][0])
246
- darso3= darso2['parts'][0]
247
- darso4= json.loads(json.dumps(darso3))
248
- #print("4|",darso4['content'])
249
- darso5= darso4['content']
250
- darso5=darso5.split('```', 2)
251
- darso5=darso5[1]
252
- #print("5a|",darso5)
253
- darso5=darso5.replace('json', '')
254
- print("5|",darso5,"|")
255
- try:
256
- darso6= json.loads(darso5) #json
257
- darso7= SalesOrder.model_validate(darso6)
258
- except:
259
- darso6= "ERR"
260
- print("6|",darso6,"|")
261
- if "ds_items" in darso5:
262
- cek_str="ds_items"
263
- else:
264
- cek_str="--"
265
- if darso6=="ERR":
266
- ds_id = time.time()
267
- ds_salesOrderId = "ERR"
268
- ds_salesDate = 'ERR'
269
- ds_customerName="-"
270
- ds_customerAddress="-"
271
-
272
- ds_productName1 = "Produk1 --- "
273
- ds_quantity1 = 1
274
- ds_unitPrice1 = 0
275
- ds_itemAmt1 = 0
276
-
277
- ds_productName2 = "Produk2 --- "
278
- ds_quantity2 = 0
279
- ds_unitPrice2 = 0
280
- ds_itemAmt2 = 0
281
-
282
- ds_productName3 = "Produk3 --- "
283
- ds_quantity3 = 0
284
- ds_unitPrice3 = 0
285
- ds_itemAmt3 = 0
286
- ds_shippingAddress=""
287
- ds_shippingCost=0
288
- ds_totalAmount=0
289
- else:
290
- ds_id = time.time()
291
- ds_salesOrderId = "OK"
292
- ds_salesDate = 'OK'
293
- try:
294
- ds_salesOrderId = darso7.ds_salesOrderId
295
- print("7|ds_salesOrderId")
296
- ds_salesDate = darso7.ds_salesDate
297
- print("7|ds_salesDate")
298
- ds_customerName=f"""{darso7.ds_customerName}"""
299
- print("7|ds_customerName:",ds_customerName)
300
- ds_customerAddress=f"""{darso7.ds_customerAddress}"""
301
- print("7|ds_customerAddress:", len(darso7.ds_items))
302
- ds_productName1 = darso7.ds_items[0].ds_productName
303
- print("7|ds_productName1")
304
- ds_quantity1 = darso7.ds_items[0].ds_quantity
305
- print("7|ds_quantity1")
306
- ds_unitPrice1 = darso7.ds_items[0].ds_unitPrice
307
- print("7|ds_unitPrice1")
308
- ds_itemAmt1 = darso7.ds_items[0].ds_itemAmt
309
- print("7|ds_itemAmt1")
310
- ds_productName2 = "-"
311
- ds_quantity2 = 0
312
- ds_unitPrice2 = 0
313
- ds_itemAmt2 = 0
314
- ds_productName3 = "-"
315
- ds_quantity3 = 0
316
- ds_unitPrice3 = 0
317
- ds_itemAmt3 = 0
318
-
319
- if len(darso7.ds_items)>1:
320
- ds_productName2 = darso7.ds_items[1].ds_productName
321
- ds_quantity2 = darso7.ds_items[1].ds_quantity
322
- ds_unitPrice2 = darso7.ds_items[1].ds_unitPrice
323
- ds_itemAmt2 = darso7.ds_items[1].ds_itemAmt
324
- if len(darso7.ds_items)>2:
325
- ds_productName3 = darso7.ds_items[2].ds_productName
326
- ds_quantity3 = darso7.ds_items[2].ds_quantity
327
- ds_unitPrice3 = darso7.ds_items[2].ds_unitPrice
328
- ds_itemAmt3 = darso7.ds_items[2].ds_itemAmt
329
-
330
- ds_shippingCost=darso7.ds_shippingCost
331
- print("7|ds_shippingCost")
332
- ds_shippingAddress=f"""{darso7.ds_shippingAddress}"""
333
- print("7|ds_shippingAddress")
334
- ds_totalAmount=darso7.ds_totalAmount
335
- print("7|ds_totalAmount")
336
- except:
337
- ds_salesOrderId = "OK2"
338
- ds_salesDate = 'OK2'
339
- ds_customerName="-"
340
- ds_customerAddress="-"
341
-
342
- ds_productName1 = "Produk1"
343
- ds_quantity1 = 0
344
- ds_unitPrice1 = 0
345
- ds_itemAmt1 = 0
346
-
347
- ds_productName2 = "Produk2"
348
- ds_quantity2 = 0
349
- ds_unitPrice2 = 0
350
- ds_itemAmt2 = 0
351
-
352
- ds_productName3 = "Produk3"
353
- ds_quantity3 = 0
354
- ds_unitPrice3 = 0
355
- ds_itemAmt3 = 0
356
- ds_shippingAddress=""
357
- ds_shippingCost=0
358
- ds_totalAmount=0
359
-
360
- formDs = f"""
361
-
362
- <form id="myaiForm{ds_id}" action="javascript:abcde({ds_id});" class="form-container">
363
- <h3>Pesanan</h3>
364
- <table>
365
- <tr>
366
- <td><label for="ds_salesOrderId"><b>SO#</b></label><input type="text" placeholder="" name="ds_salesOrderId" value="{ds_salesOrderId}"></td>
367
- <td><label for="ds_salesDate"><b>Date</b></label><input type="text" placeholder="" name="ds_salesDate" value="{ds_salesDate}"></td>
368
- </tr>
369
- <tr>
370
- <td colspan="2"><label for="ds_customerName"><b>Customer</b></label><input type="text" placeholder="" name="ds_customerName" value="{ds_customerName}"></td>
371
- </tr>
372
- <tr>
373
- <td colspan="2"><label for="ds_customerAddress"><b>Alamat</b></label><input type="text" placeholder="" name="ds_customerAddress" value="{ds_customerAddress}"></td>
374
- </tr>
375
- </table style="width:100%">
376
- <b>Item Barang:</b>
377
- <table>
378
- <tr><th>Prod</th><th>Qty</th><th>Prc</th><th>Rp</th></tr>
379
- <tr>
380
- <td><input type="text" placeholder="-" name="ds_productName1" value="{ds_productName1}"></td>
381
- <td><input type="text" placeholder="0" name="ds_quantity1" value={ds_quantity1}></td>
382
- <td><input type="text" placeholder="0" name="ds_unitPrice1" value={ds_unitPrice1}></td>
383
- <td><input type="text" placeholder="0" name="ds_itemAmt1" value={ds_itemAmt1}></td>
384
- </tr>
385
- <tr>
386
- <td><input type="text" placeholder="-" name="ds_productName2" value="{ds_productName2}"></td>
387
- <td><input type="text" placeholder="0" name="ds_quantity2" value={ds_quantity2}></td>
388
- <td><input type="text" placeholder="0" name="ds_unitPrice2" value={ds_unitPrice2}></td>
389
- <td><input type="text" placeholder="0" name="ds_itemAmt2" value={ds_itemAmt2}></td>
390
- </tr>
391
- <tr>
392
- <td><input type="text" placeholder="-" name="ds_productName3" value="{ds_productName3}"></td>
393
- <td><input type="text" placeholder="0" name="ds_quantity3" value={ds_quantity3}></td>
394
- <td><input type="text" placeholder="0" name="ds_unitPrice3" value={ds_unitPrice3}></td>
395
- <td><input type="text" placeholder="0" name="ds_itemAmt3" value={ds_itemAmt3}></td>
396
- </tr>
397
- </table>
398
- <table>
399
- <tr>
400
- <td><label for="ds_shippingCost"><b>Ongkir</b></label><input type="text" placeholder="0" name="ds_shippingCost" value={ds_shippingCost}></td>
401
- <td><label for="ds_totalAmount"><b>Total</b></label><input type="text" placeholder="0" name="ds_totalAmount" value={ds_totalAmount}></td>
402
- </tr>
403
- <tr>
404
- <td colspan="2"><label for="ds_shippingAddress"><b></b></label><input type="text" placeholder="" name="ds_shippingAddress" value="{ds_shippingAddress}"></td>
405
- </tr>
406
- </table>
407
- <button type="submit" class="btn">Submit</button>
408
- <button type="button" class="btn cancel" onclick="closeAiForm({ds_id})">Close</button>
409
- </form>
410
- <form id="myaiForm2{ds_id}" class="form-container" style="display:none;">
411
- <button type="button" class="btn umum" onclick="openAiForm({ds_id})">Open Form</button>
412
- </form>
413
- """
414
- m = ModelResponse.from_text(content=formDs, timestamp=result.timestamp())
415
- yield json.dumps(to_ds_message(m)).encode('utf-8') + b'\n'
416
- print("OK")
417
- ##print(len(items))
418
- #darso7 = SalesOrder.model_validate(darso6)
419
- #print("[--",darso7.ds_customerName,"--]")
420
- #darso8 = darso7.ds_items[0]
421
- ##, len(darso7.ds_items)
422
- #print("[--",darso8.ds_productName,"--]")
423
- except ValueError as e:
424
- print(e)
425
- if prompt[0] == "@" :
426
- #print("@@@", prompt, "@@@")
427
- nn = len(prompt)
428
- prompt = prompt[1:nn]
429
- print(">>>", prompt, "<<<")
430
- return StreamingResponse(ds_messages(prompt), media_type='text/plain')
431
- elif prompt[0] != "@" :
432
- print("biasa")
433
- return StreamingResponse(stream_messages(), media_type='text/plain')
434
- print("** selesai **")
435
- return StreamingResponse(stream_messages(), media_type='text/plain')
436
-
437
- P = ParamSpec('P')
438
- R = TypeVar('R')
439
-
440
-
441
- @dataclass
442
- class Database:
443
- """Rudimentary database to store chat messages in SQLite.
444
-
445
- The SQLite standard library package is synchronous, so we
446
- use a thread pool executor to run queries asynchronously.
447
- """
448
-
449
- con: sqlite3.Connection
450
- _loop: asyncio.AbstractEventLoop
451
- _executor: ThreadPoolExecutor
452
-
453
- @classmethod
454
- @asynccontextmanager
455
- async def connect(
456
- cls, file: Path = THIS_DIR / '.chat_messages.sqlite'
457
- ) -> AsyncIterator[Database]:
458
- with logfire.span('connect to DB'):
459
- loop = asyncio.get_event_loop()
460
- executor = ThreadPoolExecutor(max_workers=1)
461
- con = await loop.run_in_executor(executor, cls._connect, file)
462
- slf = cls(con, loop, executor)
463
- try:
464
- yield slf
465
- finally:
466
- await slf._asyncify(con.close)
467
-
468
- @staticmethod
469
- def _connect(file: Path) -> sqlite3.Connection:
470
- con = sqlite3.connect(str(file))
471
- con = logfire.instrument_sqlite3(con)
472
- cur = con.cursor()
473
- cur.execute(
474
- 'CREATE TABLE IF NOT EXISTS messages (id INT PRIMARY KEY, message_list TEXT);'
475
- )
476
- con.commit()
477
- return con
478
-
479
- async def add_messages(self, messages: bytes):
480
- await self._asyncify(
481
- self._execute,
482
- 'INSERT INTO messages (message_list) VALUES (?);',
483
- messages,
484
- commit=True,
485
- )
486
- await self._asyncify(self.con.commit)
487
-
488
- async def get_messages(self) -> list[ModelMessage]:
489
- c = await self._asyncify(
490
- self._execute, 'SELECT message_list FROM messages order by id asc'
491
- )
492
- rows = await self._asyncify(c.fetchall)
493
- messages: list[ModelMessage] = []
494
- for row in rows:
495
- messages.extend(ModelMessagesTypeAdapter.validate_json(row[0]))
496
- return messages
497
-
498
- def _execute(
499
- self, sql: LiteralString, *args: Any, commit: bool = False
500
- ) -> sqlite3.Cursor:
501
- cur = self.con.cursor()
502
- cur.execute(sql, args)
503
- if commit:
504
- self.con.commit()
505
- return cur
506
-
507
- async def _asyncify(
508
- self, func: Callable[P, R], *args: P.args, **kwargs: P.kwargs
509
- ) -> R:
510
- return await self._loop.run_in_executor( # type: ignore
511
- self._executor,
512
- partial(func, **kwargs),
513
- *args, # type: ignore
514
- )
515
-
516
-
517
- if __name__ == '__main__':
518
- import uvicorn
519
- uvicorn.run(
520
- 'start:app', reload=True, reload_dirs=[str(THIS_DIR)]
521
- )