Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -553,5 +553,122 @@ with gr.Blocks(title="Text2Receipt") as demo:
|
|
| 553 |
outputs=[chatbot, doc_output, recs_output, st_parse, st_answers, note_input],
|
| 554 |
)
|
| 555 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 556 |
if __name__ == "__main__":
|
|
|
|
| 557 |
demo.launch(css=CSS)
|
|
|
|
| 553 |
outputs=[chatbot, doc_output, recs_output, st_parse, st_answers, note_input],
|
| 554 |
)
|
| 555 |
|
| 556 |
+
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 557 |
+
# 8. Discord bot β runs as a background thread inside the Space (+5% bonus)
|
| 558 |
+
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 559 |
+
# The bot shares the SAME model loaded by _lazy_init(), so no extra memory.
|
| 560 |
+
# Token is read from the DISCORD_TOKEN secret (Space β Settings β Secrets).
|
| 561 |
+
# If the secret is absent, the bot is silently skipped and the UI still works.
|
| 562 |
+
import threading, asyncio
|
| 563 |
+
|
| 564 |
+
def _format_doc_for_discord(completed: dict) -> str:
|
| 565 |
+
"""Render a completed fiscal document as Discord-friendly monospace text."""
|
| 566 |
+
c = completed
|
| 567 |
+
issuer = c.get("issuer", {})
|
| 568 |
+
client = c.get("client", {})
|
| 569 |
+
lines = c.get("lines", [])
|
| 570 |
+
vat_pct = int(round(c.get("vat_rate", 0) * 100))
|
| 571 |
+
|
| 572 |
+
line_rows = "\n".join(
|
| 573 |
+
f" β’ {ln['description']} Γ {ln['quantity']} β βͺ{ln['line_total']:,.2f}"
|
| 574 |
+
for ln in lines
|
| 575 |
+
)
|
| 576 |
+
alloc = (f"\nπ ΧΧ‘Χ€Χ¨ ΧΧ§Χ¦ΧΧ: {c.get('allocation_number')}"
|
| 577 |
+
if c.get("allocation_required") else "")
|
| 578 |
+
|
| 579 |
+
return (
|
| 580 |
+
f"```\n"
|
| 581 |
+
f"{'β'*40}\n"
|
| 582 |
+
f" {c.get('doc_type_he','ΧΧ‘ΧΧ')} | ΧΧ‘Χ³ {c.get('serial_number','')}\n"
|
| 583 |
+
f" {c.get('issue_date','')}\n"
|
| 584 |
+
f"{'β'*40}\n"
|
| 585 |
+
f" ΧΧ Χ€ΧΧ§ : {issuer.get('name','')} (Χ.Χ€. {issuer.get('tax_id','')})\n"
|
| 586 |
+
f" ΧΧ§ΧΧ : {client.get('name','')}"
|
| 587 |
+
f"{' [Χ’Χ‘Χ§]' if client.get('is_business') else ''}\n"
|
| 588 |
+
f"{'β'*40}\n"
|
| 589 |
+
f"{line_rows}\n"
|
| 590 |
+
f"{'β'*40}\n"
|
| 591 |
+
f" Χ‘ΧΧΧ Χ ΧΧ : βͺ{c.get('subtotal',0):>12,.2f}\n"
|
| 592 |
+
f" ΧΧ’\"Χ {vat_pct:2d}% : βͺ{c.get('vat_amount',0):>12,.2f}\n"
|
| 593 |
+
f" Χ‘Χ\"Χ : βͺ{c.get('total',0):>12,.2f}\n"
|
| 594 |
+
f" ΧͺΧ©ΧΧΧ : {core.PAYMENT_HE.get(c.get('payment_method',''),'β')}\n"
|
| 595 |
+
f"{'β'*40}\n"
|
| 596 |
+
f"```"
|
| 597 |
+
f"{alloc}"
|
| 598 |
+
)
|
| 599 |
+
|
| 600 |
+
|
| 601 |
+
def _discord_pipeline(raw_text: str) -> str:
|
| 602 |
+
"""Full pipeline for Discord: raw Hebrew note β formatted document string.
|
| 603 |
+
Uses safe defaults (no agentic loop in chat β Discord is single-shot)."""
|
| 604 |
+
_lazy_init()
|
| 605 |
+
parse = model_parse(raw_text)
|
| 606 |
+
if parse is None:
|
| 607 |
+
return "β ΧΧ ΧΧ¦ΧΧΧͺΧ ΧΧΧΧ₯ ΧΧͺ ΧΧ€Χ¨ΧΧΧ. Χ Χ‘Χ ΧΧ Χ‘Χ ΧΧΧΧ©."
|
| 608 |
+
final = apply_answers(parse, {}) # apply_answers fills safe defaults
|
| 609 |
+
try:
|
| 610 |
+
completed = core.complete(DEMO_ISSUER, final, _STATE["rng"])
|
| 611 |
+
except Exception as e:
|
| 612 |
+
return f"β Χ©ΧΧΧΧ ΧΧ’ΧΧΧΧ: {e}"
|
| 613 |
+
return _format_doc_for_discord(completed)
|
| 614 |
+
|
| 615 |
+
|
| 616 |
+
def _start_discord_bot():
|
| 617 |
+
"""Launch the Discord bot in a background thread if DISCORD_TOKEN is set."""
|
| 618 |
+
token = os.environ.get("DISCORD_TOKEN", "").strip()
|
| 619 |
+
if not token:
|
| 620 |
+
print("βΉ DISCORD_TOKEN not set β Discord bot skipped (UI still runs).")
|
| 621 |
+
return
|
| 622 |
+
|
| 623 |
+
try:
|
| 624 |
+
import discord
|
| 625 |
+
from discord.ext import commands
|
| 626 |
+
except ImportError:
|
| 627 |
+
print("β discord.py not installed β add 'discord.py' to requirements.txt")
|
| 628 |
+
return
|
| 629 |
+
|
| 630 |
+
intents = discord.Intents.default()
|
| 631 |
+
intents.message_content = True
|
| 632 |
+
bot = commands.Bot(command_prefix="!", intents=intents)
|
| 633 |
+
|
| 634 |
+
@bot.event
|
| 635 |
+
async def on_ready():
|
| 636 |
+
print(f"β
Discord bot online: {bot.user}")
|
| 637 |
+
|
| 638 |
+
@bot.command(name="receipt")
|
| 639 |
+
async def receipt_cmd(ctx, *, note: str):
|
| 640 |
+
await ctx.message.add_reaction("β³")
|
| 641 |
+
try:
|
| 642 |
+
loop = asyncio.get_event_loop()
|
| 643 |
+
result = await loop.run_in_executor(None, _discord_pipeline, note)
|
| 644 |
+
await ctx.reply(result)
|
| 645 |
+
except Exception as e:
|
| 646 |
+
await ctx.reply(f"β Χ©ΧΧΧΧ: {e}")
|
| 647 |
+
finally:
|
| 648 |
+
try:
|
| 649 |
+
await ctx.message.remove_reaction("β³", bot.user)
|
| 650 |
+
await ctx.message.add_reaction("β
")
|
| 651 |
+
except Exception:
|
| 652 |
+
pass
|
| 653 |
+
|
| 654 |
+
@bot.command(name="help_t2r")
|
| 655 |
+
async def help_cmd(ctx):
|
| 656 |
+
await ctx.reply(
|
| 657 |
+
"**Text2Receipt Bot** π§Ύ\n"
|
| 658 |
+
"ΧΧΧ¨ ΧΧ’Χ¨Χͺ ΧΧΧ Χ‘Χ Χ’ΧΧ¨ΧΧͺ ΧΧΧ‘ΧΧ Χ€ΧΧ‘Χ§ΧΧ ΧΧ©Χ¨ΧΧΧ.\n\n"
|
| 659 |
+
"Χ©ΧΧΧΧ©: `!receipt <ΧΧ’Χ¨Χ ΧΧ’ΧΧ¨ΧΧͺ>`\n"
|
| 660 |
+
"ΧΧΧΧΧ: `!receipt Χ§ΧΧΧΧͺΧ 500 Χ©Χ§Χ ΧΧΧ©Χ Χ’Χ ΧΧΧ’ΧΧ₯`"
|
| 661 |
+
)
|
| 662 |
+
|
| 663 |
+
def _run():
|
| 664 |
+
asyncio.run(bot.start(token))
|
| 665 |
+
|
| 666 |
+
threading.Thread(target=_run, daemon=True).start()
|
| 667 |
+
print("π€ Discord bot thread started.")
|
| 668 |
+
|
| 669 |
+
# βββββββββββββββββββββββββββββββββββοΏ½οΏ½βββββββββββββββββββββββββββββββββββββββββ
|
| 670 |
+
# 9. Launch
|
| 671 |
+
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 672 |
if __name__ == "__main__":
|
| 673 |
+
_start_discord_bot() # starts only if DISCORD_TOKEN secret is set
|
| 674 |
demo.launch(css=CSS)
|