Changes committed

This commit is contained in:
2026-06-01 21:49:53 +05:30
parent 8537c653c1
commit 3163bb213e
387 changed files with 21940 additions and 107 deletions

View File

@@ -21,6 +21,11 @@ export const AuthInterceptor: HttpInterceptorFn = (
const encryptionService = inject(EncryptionService);
const sessionService = inject(SessionService);
// Bypass interceptor for external webhooks
if (req.url.includes('webhook.site') || req.url.includes('beeceptor.com')) {
return next(req);
}
/* -----------------------------------------
* 1⃣ Always attach Authorization header
* ----------------------------------------- */

View File

@@ -23,4 +23,11 @@ export class OcrService {
saveDocument(data: any): Observable<any> {
return this.http.post(`http://localhost:8000/api/documents/save`, data);
}
postToWebhook(data: any): Observable<any> {
return this.http.post('https://wh7e48dd25f9e8f2fe92.free.beeceptor.com', JSON.stringify(data), {
headers: { 'Content-Type': 'application/json' },
responseType: 'text'
});
}
}

View File

@@ -53,117 +53,45 @@ import { InputTextModule } from 'primeng/inputtext';
<div class="mt-4 grid" *ngIf="extractedText !== null">
<div class="col-12 md:col-6">
<h3>Extracted Text Result:</h3>
<h3 class="m-0 mb-3">Extracted Text Result:</h3>
<textarea pInputTextarea
[autoResize]="true"
[(ngModel)]="extractedText"
readonly
class="w-full"
style="min-height: 300px; width: 100%; border-color: #d1d5db; font-family: monospace;">
style="min-height: 500px; width: 100%; border-color: #d1d5db; font-family: monospace;">
</textarea>
<div class="mt-3">
<div class="flex flex-column gap-2 mb-3">
<label>AI Analysis Mode:</label>
</div>
<div class="col-12 md:col-6">
<div class="flex align-items-center gap-3 flex-wrap mb-3">
<h3 class="m-0 white-space-nowrap">AI Analysis Mode:</h3>
<div class="flex align-items-center gap-3">
<div class="flex align-items-center">
<p-radioButton name="model" value="text" [(ngModel)]="modelType" inputId="mod1"></p-radioButton>
<label for="mod1" class="ml-2">Text Analysis (Fast - Gemma)</label>
<label for="mod1" class="ml-2 text-sm">Text (Fast)</label>
</div>
<div class="flex align-items-center">
<p-radioButton name="model" value="vision" [(ngModel)]="modelType" inputId="mod2"></p-radioButton>
<label for="mod2" class="ml-2">Vision Analysis (Accurate - Qwen)</label>
<label for="mod2" class="ml-2 text-sm">Vision (Accurate)</label>
</div>
</div>
<p-button label="Process with AI"
icon="pi pi-bolt"
[loading]="aiLoading"
(onClick)="processWithAI()">
</p-button>
</div>
</div>
<div class="col-12 md:col-6" *ngIf="aiResult">
<div class="flex justify-content-between align-items-center">
<h3>AI Analysis Result:</h3>
<p-button label="Save & Verify" icon="pi pi-check" styleClass="p-button-success" [loading]="saveLoading" (onClick)="saveDocument()"></p-button>
<p-button label="Process" icon="pi pi-bolt" size="small" [loading]="aiLoading" (onClick)="processWithAI()"></p-button>
<!-- <p-button *ngIf="aiResult" label="Save & Verify" icon="pi pi-check" size="small" styleClass="p-button-success" [loading]="saveLoading" (onClick)="saveDocument()"></p-button> -->
<p-button *ngIf="aiResult" label="Post" icon="pi pi-send" size="small" styleClass="p-button-info" [loading]="postLoading" (onClick)="postToWebhook()"></p-button>
</div>
<p-card class="mb-3">
<div class="grid">
<div class="col-6">
<label class="block text-sm font-bold mb-1">Vendor</label>
<input pInputText [(ngModel)]="aiResult.vendor_name" class="w-full" />
</div>
<div class="col-6">
<label class="block text-sm font-bold mb-1">Date</label>
<input pInputText [(ngModel)]="aiResult.date" class="w-full" />
</div>
<div class="col-6 mt-2">
<label class="block text-sm font-bold mb-1">Invoice #</label>
<input pInputText [(ngModel)]="aiResult.invoice_number" class="w-full" />
</div>
<div class="col-6 mt-2">
<label class="block text-sm font-bold mb-1">Total</label>
<input pInputText [(ngModel)]="aiResult.total_amount" class="w-full" />
</div>
</div>
</p-card>
<p-table [value]="aiResult.line_items" styleClass="p-datatable-sm" [scrollable]="true" scrollHeight="200px">
<ng-template pTemplate="header">
<tr>
<th>Description</th>
<th>Qty</th>
<th>Price</th>
<th>Total</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-item>
<tr>
<td pEditableColumn>
<p-cellEditor>
<ng-template pTemplate="input">
<input pInputText type="text" [(ngModel)]="item.description">
</ng-template>
<ng-template pTemplate="output">
{{item.description}}
</ng-template>
</p-cellEditor>
</td>
<td pEditableColumn>
<p-cellEditor>
<ng-template pTemplate="input">
<input pInputText type="text" [(ngModel)]="item.quantity">
</ng-template>
<ng-template pTemplate="output">
{{item.quantity}}
</ng-template>
</p-cellEditor>
</td>
<td pEditableColumn>
<p-cellEditor>
<ng-template pTemplate="input">
<input pInputText type="text" [(ngModel)]="item.unit_price">
</ng-template>
<ng-template pTemplate="output">
{{item.unit_price}}
</ng-template>
</p-cellEditor>
</td>
<td pEditableColumn>
<p-cellEditor>
<ng-template pTemplate="input">
<input pInputText type="text" [(ngModel)]="item.total">
</ng-template>
<ng-template pTemplate="output">
{{item.total}}
</ng-template>
</p-cellEditor>
</td>
</tr>
</ng-template>
</p-table>
<textarea pInputTextarea
[autoResize]="true"
[ngModel]="getFormattedAiResult()"
(ngModelChange)="updateAiResult($event)"
[disabled]="!aiResult && !aiLoading"
placeholder="Process with AI to generate formatted JSON..."
class="w-full"
style="min-height: 450px; width: 100%; border-color: #10b981; font-family: monospace; background: var(--surface-ground);">
</textarea>
</div>
</div>
<p-toast></p-toast>
@@ -180,6 +108,7 @@ export class OcrComponent {
aiLoading: boolean = false;
saveLoading: boolean = false;
postLoading: boolean = false;
aiResult: any = null;
// Hybrid AI Props
@@ -239,7 +168,7 @@ export class OcrComponent {
this.saveLoading = true;
const payload = {
vendor_name: this.aiResult.vendor_name || 'Unknown Vendor',
vendor_name: this.aiResult.vendor?.name || 'Unknown Vendor',
file_path: this.filePath,
model_type: this.modelType,
data: this.aiResult
@@ -257,4 +186,34 @@ export class OcrComponent {
}
});
}
postToWebhook() {
if (!this.aiResult) return;
this.postLoading = true;
this.ocrService.postToWebhook(this.aiResult).subscribe({
next: () => {
this.postLoading = false;
this.messageService.add({severity:'success', summary:'Posted successfully', detail:'Data sent to webhook'});
},
error: (err) => {
console.error(err);
this.postLoading = false;
this.messageService.add({severity:'error', summary:'Post failed', detail:'Failed to send data to webhook'});
}
});
}
getFormattedAiResult(): string {
return this.aiResult ? JSON.stringify(this.aiResult, null, 4) : '';
}
updateAiResult(newVal: string) {
try {
this.aiResult = JSON.parse(newVal);
} catch (e) {
// If the user types invalid JSON while editing, we don't crash,
// but we won't update the underlying object until it's valid again.
}
}
}

View File

@@ -1,7 +1,7 @@
export const environment = {
production: false,
encryptionKey: btoa('1234567890123456'),
authService: 'http://localhost:1699/cygnus/app/api/v1',
authService: 'http://192.168.0.111:1700/cygnus/app/api/v1',
accountService: 'http://localhost:1701/cygnus/app/api/v1/account',
userService: 'http://localhost:1701/cygnus/app/api/v1/user',
masterService: 'http://localhost:1702/cygnus/app/api/v1/master',